In Gatsby how can I create a resolver that uses data loaded by the gatsby-source-graphql plugin. I'm having trouble figuring out to query the data inside a resolver. Can this be done? Any advice on what I'm missing would be helpful.
something like this in gatsby-node.js ...
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Query: {
getStructure: {
type: `Structure`,
async resolve(source, args, context, info) {
// assume gatsby-config.js is configured with gatsby-source-graphql and this node exists
const myGraphQlApiNode = await context.nodeModel.runQuery({
query: {
filter: {
fieldName: { eq: "myGqlApi" }
}
},
type: "GraphQLSource"
});
const someGqlApiData = // query all of type MyGqlApi_SomeTypeFromGqlApi loaded via gatsby-source-graphql
return toStructure(someGqlApiData)
}
}
}
});
};
It may be an unofficial solution
Because gatsby doesn’t provide graphql method in createResolvers but do it on createPages
you can do st like this
in gatsby-node.js
let apiHelperGraphql = null
exports.createPages = async ({ actions, graphql }) => {
// steal it from create Pages
apiHelperGraphql = graphql
}
exports.createResolvers = ({ createResolvers }) => {
// and call it here, do what ever you want
apiHelperGraphql(`same as grapql syntax`)
}
Related
let root = {
books: (parent, args, info) { ... }
}
let res = await graphql(schema, `{ books { title } }`, root);
Is there already a helper function in graphql.js to reconstruct the query using the info?
yes there is a way:
When you use graphqlHTTP from express-graphql, the 3rd argument is graphQLParams, you can give it the context for instance.
graphqlHTTP(async (request, response, graphQLParams) => ({
schema,
graphiql: true,
context: graphQLParams
}))
Then in your schema definition, you can grab the context from any resolve function like this:
products: {
type: new GraphQLList(productType),
resolve: (parent, args, { query }, info) => {
return getProducts({
query
});
}
},
context.query is your actual query in this example its:
{ products { id } }
I am trying out the basic implementation for Apollo server for GraphQL with my REST API calls as Data Sources. I do not see any data returned from the same even though there is data returned when I call the API separately. Can anyone help figure out what could be going wrong?
PS: I have CORS enabled on my API so not sure if I am passing that too correctly. I do not have any idea how to figure out what URL this is calling.
My sample code below:
const { ApolloServer, gql } = require('apollo-server');
const { RESTDataSource } = require('apollo-datasource-rest');
class Contact extends RESTDataSource {
constructor() {
super();
this.baseURL = 'http://localhost:8080/objects/';
}
async getContactById(id) {
return this.get(`contact/${id}`);
}
async getAllContacts() {
const data = await this.get(`contact`);
return data.results;
}
// an example making an HTTP PUT request
async newContact(contact) {
return this.put(
'contact', // path
contact, // request body
);
}
};
// Type definitions define the "shape" of your data and specify
// which ways the data can be fetched from the GraphQL server.
const typeDefs = gql`
# Comments in GraphQL are defined with the hash (#) symbol.
type Query {
allContacts: [Contact]
contactById(id: ID): Contact
}
type Contact {
id: ID
contact_name: String
}
`;
// Resolvers define the technique for fetching the types in the
// schema.
const resolvers = {
Query: {
contactById: async (_source, { id }, { dataSources }) => {
return dataSources.contact.getContactById(id);
},
allContacts: async (_source, _args, { dataSources }) => {
return dataSources.contact.getAllContacts();
},
},
};
// In the most basic sense, the ApolloServer can be started
// by passing type definitions (typeDefs) and the resolvers
// responsible for fetching the data for those types.
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => {
return {
contact : new Contact(),
};
},
cors : true,
});
// This `listen` method launches a web-server. Existing apps
// can utilize middleware options, which we'll discuss later.
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Below is the request and response from the GraphQL playground:
query {
contactById (id : 5) {
id
contact_name
}
}
Response:
{
"data": {
"contactById": {
"id": null,
"contact_name": null
}
}
}
Hello i have a gatsbyjs site that i tried to pull data of model 'job' from graphcms. if i pull alljob. the query works fine but if i try to put condition to pull only the job with the status field pubished. it didnt pull any data and throw an error:
TypeError: Cannot read property 'allJob' of undefined
Here's my gatsby-node.js:
const path = require(`path`);
const makeRequest = (graphql, request) => new Promise((resolve, reject) => {
resolve(
graphql(request).then(result => {
if (result.errors) {
reject(result.errors)
}
return result;
})
)
});
exports.createPages = ({ boundActionCreators, graphql }) => {
const { createPage } = boundActionCreators;
const getJobs = makeRequest(graphql, `
{
allJob(where: {status: PUBLISHED}) {
edges{
node{
id
}
}
}
}
`).then(result => { result.data.allJob.edges.forEach(({ node }) => {
createPage({
path: `/job/${node.id}`,
component: path.resolve(`src/templates/jobTemplate.js`),
context: {
id: node.id,
}
})
console.log(node.id)
})
}
)
return getJobs;
};
Gatsby doesn't understand allJob(where: {status: PUBLISHED}) as it's the wrong syntax.
You would want to use filter instead. I can't give you an example as I don't know how the structure is but can advise you to run gatsby develop and go to GraphiQL (http://localhost:8000/___graphql) and use it's autocomplete feature (Ctrl + Space) to get the right filter.
More information: https://www.gatsbyjs.org/docs/graphql-reference/#filter
Is it possible to return a random graphql element from a Graphcool backend? If so, how could this be done?
Alternatively, any tips on howto create custom queries for Graphcool backends?
The best way to do this is by using the API Gateway pattern.
The idea of that approach is to put a gateway server on top of Graphcool's CRUD API and thus customize the API. With this approach, you'd write an additional resolver function that retrieves the random element for you:
const extendTypeDefs = `
extend type Query {
randomItem: Item
}
`
const mergedSchemas = mergeSchemas({
schemas: [graphcoolSchema, extendTypeDefs],
resolvers: mergeInfo => ({
Query: {
randomItem: {
resolve: () => {
return request(endpoint, allItemsQuery).then(data => {
const { count } = data._allItemsMeta
const randomIndex = Math.floor((Math.random() * (count-1)) + 0)
const { id } = data.allItems[randomIndex]
return request(endpoint, singleItemQuery, { id }).then(data => data.Item)
})
},
}
},
}),
})
I created a full example of this here. Let me know if you have any additional questions :)
Why isn't updateQueries getting called for me? I think I'm doing exactly what the docs say and have compared my code to other similar questions. What am I missing?
Package versions:
apollo-angular#0.13.0
apollo-client#1.0.4
My code:
//same es6 module, above my class definition
const RecentSearchesQuery = gql`
query recentSearch {
recentSearch {
id
query
lastUpdated
userId
}
}
`;
const RecentSearchesMutation = gql`
mutation recentSearchSave($query:String!) {
recentSearchSave(query: $query)
}
`;
...
//my class method
updateRecentSearches(query: string) {
const updateQueries: MutationQueryReducersMap = {
RecentSearch: (prev: Object, {mutationResult}) => {
//execution doesn't get here
debugger;
alert('updateQueries handler in RecentSearchesMutation mutation for recentSearch');
...
}
};
return new Promise((resolve, reject) => {
this.apollo.mutate<any>({
mutation: RecentSearchesMutation,
variables: {query},
updateQueries
})
.subscribe({
next: ({data}) => {
resolve();
},
error: (error: ApolloError) => {
reject(error);
}
});
});
I never did get updateQueries working but the recommended way is now to use update (also a mutation option). Using update worked for me and this article was a very helpful:
https://dev-blog.apollodata.com/apollo-clients-new-imperative-store-api-6cb69318a1e3