Gatsby and GraphQL: query pdf file using <StaticQuery/> - graphql

I am very new to graphQL.
Inside src I have a data folder which contains a pdf named my_cv.pdf
Problem: I am unable to either load it in the browser or able to download it. I get an error There's not a page yet at /data.file.publicURL
gatsby.config.js
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/data/`,
name: "data",
},
},
my hero component
this is inside the render() of the class component.
<Resume href="data.file.publicURL" target="_blank">
Download Resume
</Resume>
this is how I am querying it.
<StaticQuery
query={graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
</StaticQuery>

The problem is that you are aliasing file as pdf, hence the nesting should be:
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
If you use StaticQuery I think you may want to use something like:
import React from "react";
import { StaticQuery, graphql } from "gatsby";
export default function Header() {
return (
<StaticQuery
query={graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
}
`}
render={(data) => (
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
)}
/>
);
}
If you use useStaticQuery hook you can detach the logic from Resume of the StaticQuery component
import React from "react";
import { useStaticQuery, graphql } from "gatsby";
export default function Header() {
const data = useStaticQuery(graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
}
`);
return (
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
);
}
In both cases, be sure that the GraphQL query is returning valid data.

Related

Getting an error when having heuristic fragment matching with Apollo & Nuxt.js

I am trying to connect the below graphql query with nuxtjs.
query getContent($slug: String!) {
contents (filters: { slug: { eq: $slug } }) {
data {
id
attributes {
title
content {
__typename
... on ComponentContentParagraph {
content
}
}
}
}
}
}
I am getting the following error and not getting the result from the query.
You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types. Apollo Client will not be able to accurately map fragments. To make this error go away, use the `IntrospectionFragmentMatcher` as described in the docs: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher
I have checked the questions and answers available here.
Apollo+GraphQL - Heuristic Fragment Manual Matching
I have followed the docs from apollo as well.
https://www.apollographql.com/docs/react/data/fragments/#fragment-matcher
I managed to generate possibleTypes as mentioned in the docs.
Here is my next config.
apollo: {
includeNodeModules: true,
clientConfigs: {
default: "~/graphql/default.js",
},
},
This is the default.js
import { InMemoryCache } from "apollo-cache-inmemory";
import possibleTypes from "./possibleTypes.json";
export default () => {
return {
httpEndpoint: process.env.BACKEND_URL || "http://localhost:1337/graphql",
cache: new InMemoryCache({ possibleTypes }),
};
};
I am using strapi for the backend and this query works fine when running from graphql interface.

Can't query data from contentful to gatsby project

Don't get the query to contentful to work.
Receive error message:
TypeError: Cannot read property 'allContentfulMagArticle' of undefined
datais undefined inside the Posts component. Can't see what i'm doing wrong here.
import { graphql } from 'gatsby';
import Post from "./post.js";
import './posts.css';
export const query = graphql`
query {
allContentfulMagArticle{
edges{
node{
index
title
name
subHeading
extract {
raw
}
slug
}
}
}
}
`
const Posts = ({ data }) => {
return (
<section className="posts">
<ul className="post-list">
{data.allContentfulMagArticle.edges.map(({ node }) => (
<Post
key={node.index}
id={node.index}
node={node}
title={node.title}
name={node.name}
// image={node.frontmatter.featuredImage.childImageSharp.fluid}
subheading={node.subheading}
body={node.extract.raw}
/>
))}
</ul>
</section>
)
}
export default Posts
Here my gatsby-config.js:
require('dotenv').config({
path: `.env`,
})
module.exports = {
siteMetadata: {
title: `XX`,
description: `XX`,
author: `Lisa Lee`,
url: `https://www.tortmagazine.com`
},
plugins: [
`gatsby-plugin-react-helmet`,
'gatsby-plugin-fontawesome-css',
'gatsby-plugin-sharp',
`gatsby-transformer-sharp`,
`gatsby-transformer-remark`,
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/`,
},
},
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: process.env.GATSBY_CONTENTFUL_SPACE_ID,
accessToken: process.env.GATSBY_CONTENTFUL_ACCESS_TOKEN,
},
},
],
}
You used the word "component" to describe your Posts but the query you are using only works in a page, or in the context of createPage (so in a template file as well). If you are indeed in a component, that will be the issue. If not, then I'm not clear what is wrong, I use the same pattern (eg: data.edges.node.map()) and it works for me.
The only other difference I noticed is in gatsby-config, I define an environment key. I'm not sure what the behavior is if none is defined, probably defaults to master so you may also want to confirm you're on the right environment.

Gatsy page query fails to work when using named export at the end of the page. Why?

I have the following page template in Gatsby.
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
const PageTemplate = props => {
const { wordpressPage: currentPage } = props.data;
return (
<Layout>
<h1 dangerouslySetInnerHTML={{ __html: currentPage.title }} />
<div dangerouslySetInnerHTML={{ __html: currentPage.content }} />
</Layout>
);
};
export const pageQuery = graphql`
query($id: String!) {
wordpressPage(id: { eq: $id }) {
title
content
date(formatString: "MMMM DD, YYYY")
}
site {
id
siteMetadata {
title
}
}
}
`;
export default PageTemplate;
Which works as expected (taken from tutorial), however I tend to prefer to do all my exporting at the end of the page like so:
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
const PageTemplate = props => {
const { wordpressPage: currentPage } = props.data;
return (
<Layout>
<h1 dangerouslySetInnerHTML={{ __html: currentPage.title }} />
<div dangerouslySetInnerHTML={{ __html: currentPage.content }} />
</Layout>
);
};
const pageQuery = graphql`
query($id: String!) {
wordpressPage(id: { eq: $id }) {
title
content
date(formatString: "MMMM DD, YYYY")
}
site {
id
siteMetadata {
title
}
}
}
`;
export default PageTemplate;
export { pageQuery }
However this fails to work - props.data is undefined. It's a subtle difference but why would this cause the pageQuery to not execute?
I believe pageQuery has to be exported before PageTemplate because it is used by it: that's where it gets its props.data from, which explains why you are getting undefined when exporting it after.
This answer is an additional explanation to #hexangel616 who mentioned the order of exports matters:
I believe pageQuery has to be exported before PageTemplate because it is used by it.
Your exported GraphQL queries have a special role in the gatsby build process. From the docs:
At a high level, what happens during the whole bootstrap and build
process is:
Node objects are sourced from whatever sources you defined in gatsby-config.js with plugins as well as in your gatsby-node.js file
A schema is inferred from the Node objects
Pages are created based off JavaScript components in your site or in installed themes
GraphQL queries are extracted and run to provide data for all pages
Static files are created and bundled in the public directory
TLDR: In order for gatsby to build properly all your graphql exports have to be in order.

<Query syntax failing

All right. Need some fresh eyes to spot my error:
Trying to grab content for a JS Carousel from a mongo db via GraphQL (as produced by strapi).
Working in a component with relevant imports:
import { Query } from 'react-apollo'
import { gql } from 'graphql-tag'
import React, { Component } from 'react'
import { Carousel, CarouselItem, CarouselControl, CarouselIndicators, CarouselCaption } from 'reactstrap'
within my class
...snippet...
render() {
const GET_CAROUSELS = gql`
query carousels {
carousels {
_id
caption_header
caption_text
alt_text
slide_file { url }
}
}`
return (
<Query query={GET_CAROUSELS} errorPolicy="all">
{({ loading, error, data }) => {
let cars = data.carousels
if (error) console.log(error)
if (!cars || cars.length == 0){
return <div>No Carousels found</div>
} else {
return (
<React.Fragment>
<Carousel activeIndex={this.activeIndex}
next={this.next}
previous={this.previous} >
{cars.map(carousel => (
<CarouselItem key={carousel._id}>
<img scr={carousel.slide_file.url} />
</CarouselItem>
))}
</Carousel>
I've tried many permutations, and this current code errors with cannot read property of 'map' undefined
My QLGraph playground shows that this query works fine:
query {carousels {
_id
caption_header
caption_text
alt_text
slide_file { url }
}
}
I've tried altering the <Query query, to no avail. Tried with and without letting let cars = data.carousels sometimes just let cars=carousels, etc.
Help, my eyes hurt.

Autoform with Meteor React and Simple-Schema

Is there any possibility to make meteor-autoform work with meteor-collection2-core and react-meteor?
MWE
Preferably I would like to have something like this.
./imports/api/Books.js
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
const Books = new Mongo.Collection("books");
Books.attachSchema(new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
author: {
type: String,
label: "Author"
},
}));
if (Meteor.isServer) {
Meteor.publish('allBooks', function () {
return Books.find({}, );
});
};
export default Books;
./imports/client/NewBooks.js
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import { quickForm } from 'meteor-autoform';
import Books from '../api/Books';
class NewBooks extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<div className="container">
<quickForm
collection={Books}
id="insertBookForm"
type="insert">
</quickForm>
</div>
)
}
};
export default createContainer(() => {
Meteor.subscribe('allBooks');
return {
books: Books.find().fetch()
}
}, NewBooks);
The npm package Uniforms worked super easy with Bootstrap.
Addition to ./imports/client/NewBooks.js
import AutoForm from 'uniforms-unstyled/AutoForm';
...
<AutoForm
schema={Books._collection.simpleSchema()}
onSubmit={doc => console.log(doc)}
/>
To my knowledge, Autoform depends heavily on Blaze, so, you could either use blaze autoform components in react (see here), or you can use a different library for this. I used this in a recent project: github.com/nicolaslopezj/simple-react-form. It's powerful, but much more 'hands-on' than the magical Autoform (you have to write your own form and field components).

Resources