Error: BabelPluginRemoveGraphQL: String interpolations - graphql

I am getting below error when trying to pass variable dynamically in gatsBy Graphql.
Error
Module build failed (from ./node_modules/gatsby/dist/utils/babel-loader.js):
Error: BabelPluginRemoveGraphQL: String interpolations are not allowed in graphql fragments. Included fragments should be referenced as `...MyModule_foo`.
Query
let mytext = 'welcome'
let myQuery = graphql`query($text: String = "${mytext}") {
allGhostPost : allGhostPost(filter:{title:{eq: $text}}) {
edges {
node {
id
slug
}
}
}
}`
Please help!!!

Inserting arbitrary text into queries like this is a well-known security issue and the Babel plugin is almost certainly right to forbid it. GraphQL defines a JSON-over-HTTP payload format that allows passing the variables separately (encoded as JSON objects to minimize the possibility of injection attacks).
You don't show what's actually making the query, but it should have a place to add a map of GraphQL variables. (For example, the graphql-js reference implementation includes a variableValues parameter to its top-level graphql function.) Remove the = "${mytext}" part of the query, and instead use a variables object like {text: mytext}.

Related

How to workaround non existent types in Graphql query in Gatsby

I'm building a website with a blog section, and on deployment to production the blog will be empty. I'm having problems allowing an empty blog on my Gatsby site.
When I run npm run develop it will only work if I have some blogs - I want it to work before the blogs have been added.
The main issues I'm encountering is trying to accomidate fields not existing like allStrapiBlog and strapiBlog because there are no blogs.
I get errors like this on blog components, and on my nav component (where i have a query that a conditional uses).
15:17 error Cannot query field "allStrapiBlog" on type "Query" graphql/template-strings
Cannot query field "strapiBlog" on type "Query"
This is what the query looks like for my navigation component. But it throws an error - is there a way to make it just return null?
query NavigationQuery {
allStrapiBlog {
nodes {
title
strapi_id
}
totalCount
}
}
How do I make unsuccessful GraphQL queries not break the build, so I can build a gatsby site with a empty blog?
But it throws an error - is there a way to make it just return null?
Indeed, you need to configure your GraphQL schema to allow nullable fields.
You have a boilerplate that you can tweak to match your data types at https://www.virtualbadge.io/blog-articles/nullable-relational-fields-strapi-gatsbyjs-graphql.
The idea relies on using the createSchemaCustomization API in your gatsbt-node.js to add your own type definitions.
Something like:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;
const typeDefs = `
type StrapiBlogPost implements Node {
title: String!
content: String
thumbnail: File
}
`;
createTypes(typeDefs);
};
In this case, the title is required (because of the !, which means that the type is non-nullable) while content and thumbnail can be null.
Afterward, you will only need to adapt your component to avoid code-breaking logics when null data is fetched.

How are arguments added to GraphQL, do they need to be defined before?

Hi Everyone I am just trying to learn graphql as I am using Gatsby. I want to know does each field in graphql take an argument or does it need to be defined somehow before. So for example if you visit this link graphql search results
https://graphql.org/swapi-graphql?query=%7B%0A%09allPeople%20%7B%0A%09%20%20people%20%7B%0A%09%20%20%20%20id%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20birthYear%0A%20%20%20%20%20%20eyeColor%0A%09%20%20%7D%0A%09%7D%0A%7D%0A
If i wanted to limit people by eye color how would I do that. In the docs it seems easy as you would just do something like people(eyecolor: 'brown') but that doesn't seem possible. Am I missing something? I basically want to do a SQL style search for all people where eye color is brown.
Thanks.
Arguments need to be defined in the schema and implemented in the resolver. If you're consuming a 3rd party API (like the link you provided), you're limited to their schema. You can tell by looking at their schema (by clicking Docs on the right side of the page) which fields take arguments. For example, person takes id and personID arguments:
people doesn't take any arguments, as seen in the schema:
If you're building your own schema, you can add arguments to any field, and when you implement the resolver for that field you can use the arguments for logic in that resolver.
If you're working with a schema that you don't control, you'll have to add filtering on the frontend:
const {people} = data.allPeople;
const brownEyedPeople = people.filter(({eyeColor}) => eyeColor === 'brown');
When you start developing in Gatsby and actually pull your data into Gatsby, there will be a filter query option that automatically becomes available in the query arguments.
https://www.gatsbyjs.org/docs/graphql-reference/#filter
You can expect to be able to filter your people by eyeColor by using the below query:
{
allPeople(filter: { eyeColor: { eq: "brown" } }) {
edges {
node {
id
name
birthYear
eyeColor
}
}
}
}

GraphQL - Execute sub query conditionally

I'm trying to optimise the query executed by some of my react components that are shared across the whole app, such as Footer and Header components.
I'm trying not to fetch the Student Solution details when the variable institutionPath is not provided.
query organisationAndInstitution($organisationName: String!, $institutionPath: String!, $fetchInstitution: Boolean!){
organisation(where: {
name: $organisationName
}){
name
}
studentSolutionRelationships(where:{
AND: [
{
status: PUBLISHED
},
{
studentSolution: {
status: PUBLISHED
}
}
]
}) #include(if: $fetchInstitution) {
status
}
}
To do so, I added a fetchInstitution boolean variable and added the #include(if: $fetchInstitution) directive.
But directives seem to apply only on fields, not on whole queries. So I wonder if what I want to do is possible, because the way I wrote it is invalid.
Any field in a GraphQL document can be explicitly included using the #include directive or explicitly excluded using the #skip directive. The directive should be provided after the field name and arguments, but before the field's selection set, if it has one, as shown in your question:
studentSolutionRelationships(where:{
#...input fields omitted for brevity
}) #include(if: $fetchInstitution) {
status
}
The directive takes a single argument (if) which must be a Boolean value. This value may be a literal (i.e. true or false) or a variable of the Boolean type. GraphQL does not provide a way to evaluate expressions -- any conditional logic has to be reside in the client code and be used to determine the value of the variable passed to the if argument.
The directives may be applied to any field in a document, including root-level ones like studentSolutionRelationships and organisation in the question. In fact, you can exclude all root fields using these directives -- just keep in mind that in such a scenario, the query will still run and just return an empty object.
In other words, your approach here is correct. If the query is failing, it's because of an unrelated issue.

Apollo GraphQL fails to invoke resolver for a nested field

I've the following structure in my schema:
type gn_Feature implements Some_Interface {
s_description: String
s_id: URL!
some_parent: gn_Feature
}
As you can see, each gn_Feature has an another linked gn_Feature object (the linking is handled elsewhere, it doesn't really matter). By my current understanding, you only need to define the resolvers for the return types, so my resolvers look like the following:
export const resolvers = Object.assign(
{},
{
DateTime: DateTime,
Date: DateTime,
Time: RegularExpression("Time", /^\d{2}:\d{2}(:\d{2})?$/),
URL,
Query: {
gn_Feature: gn_FeatureResolver
},
gn_Feature: gn_FeatureResolver
}
);
But, my queries fail with the following error if I don't explicitly define the resolver for the nested field, like so:
gn_Feature: {some_parent: gn_FeatureResolver}
Error:
"message": "Resolve function for \"gn_Feature.s_description\"
returned undefined"
My resolver function doesn't even get invoked for my nested object when I don't specify it like the above.
My backend consists of some voodoo transpiling of GraphQL queries into SparQL queries which return data back so I won't post the resolver code as I utilize one universal resolver for many fields. I'd like to avoid having to specify resolvers for each nested field as that's going be extremely tedious (I have dozens of types with dozens of fields). Any clarifications are welcome, as I'm completely baffled.
Example GraphQL query:
gn_Feature(some_field:"AD", last:2){
s_description,
s_id
some_parent{
s_description
}
}
When executing a query, only the value of any particular field is initially unknown and needs to be resolved... everything else, like the types, selection sets, etc. is already known. A resolver is a function called to resolve a specific field. In GraphQL.js, there are no resolvers for types.
Apollo muddies the waters a bit in this regard, since for convenience, the API for makeExecutableSchema allows you to define custom scalars by including them in the resolver map. Additionally, even though interfaces and unions don't have resolvers either, Apollo lets you use the resolver map to specify a __resolveType function for these abstract types as well. Apollo's docs actually define a resolver as "a function that connects schema fields and types to various backends." However, in the context of GraphQL in general, you should think of a resolvers as "a functions that resolves the value of a field".
So, given a type called gn_Feature and a field called some_parent, this is the correct way to structure your resolvers:
const resolvers = {
gn_Feature: {
some_parent: someResolverFunction
}
}
Also note that Query and Mutation are both types themselves, so if you have a query called gn_Feature, you are actually resolving a field called gn_Feature for the Query type.

Is there a way to pass a fragment to graphiql?

It's possible to pass a query, but apparently not a fragment:
server.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
query: `# Welcome to GraphiQL
query PostsForAuthor {
author(id: 1) {
firstName
posts {
title
votes
}
}
}`}));
Update 10/12/2017
It is possible to send fragments along with a query using Apollo's client:
http://dev.apollodata.com/core/fragments.html
This is not a solution to the original question, however; I would like to pass fragments to a graphiql server instance at startup.
by startup do you mean from the server? if so I don't believe that's how fragments are used. my understanding is as follows:
on the server you provide Types (like User)
on the client you query those Types using queries and fragments
for instance, if you provide type User on the server, on the client graphQL you can use fragments to query that type:
graphQL (client)
fragment authorData on AuthorType{
firstName
posts {
title
votes
}
}
query PostsForAuthor {
author(id: 1) {
...authorData
}
}
As you noticed (and as detailed here) GraphiQL takes a query argument:
query: an optional GraphQL string to use as the initial displayed query, if undefined is provided, the stored query or defaultQuery will be used.
If putting a fragment in as the value for that argument doesn't work, then I don't believe there is any way to start with a fragment ... but really why would you even want to? A fragment by itself isn't executable, and the whole idea is to start GraphiQL with a (executable) query.
If all you want is to be able to copy/paste in some text that you use frequently in your queries, a bookmarklet might be a better idea.

Resources