Extend the GraphQL API
Learn how to extend the Headless CMS-related GraphQL types and operations.
- how to extend the Headless CMS-related GraphQL types and operations
webiny watch
command to continuously deploy application code changes into the cloud and instantly see them in action. For quick (manual) testing, you can use the built-in API Playground.Custom Queries
Let’s say we wanted to extend our GraphQL schema with a custom listMyPosts
query, which, as the name suggests, would enable us to quickly retrieve all posts created via the Headless CMS application, for the currently logged in user.
In other words, we want to return all content entries of the Post content model, where the createdBy
points to the currently logged in user. For demonstration purposes, our Post content model will be very simple:
The createdBy
field is automatically assigned to every content entry and it represents the currently logged in user.
Creating the new listMyPosts
query can be achieved via a single GraphQLSchemaPlugin
plugin.
import { GraphQLSchemaPlugin } from "@webiny/handler-graphql/plugins";
import { ListResponse } from "@webiny/handler-graphql/responses";
import { CmsEntry, CmsEntryMeta } from "@webiny/api-headless-cms/types";
// Make sure to import the `Context` interface and pass it to the `GraphQLSchemaPlugin`
// plugin. Apart from making your application code type-safe, it will also make the
// interaction with the `context` object significantly easier.
import { Context } from "~/types";
export default [
new GraphQLSchemaPlugin<Context>({
// Extend the `Query` type with the `listMyPosts` query. Note the `PostListResponse` type.
// It exists because we've previously created the `Post` content model via Admin Area.
typeDefs: /* GraphQL */ `
extend type Query {
# List posts that were created by the currently logged in user.
listMyPosts: PostListResponse
}
`,
// In order for the `listMyPosts` to work, we also need to create a resolver function.
resolvers: {
Query: {
listMyPosts: async (_, args: { id: string }, context) => {
const { security, cms } = context;
// Retrieve the `post` model.
const model = await cms.getModel("post");
// Use the `cms.listLatestEntries` method to fetch latest entries for the currently
// logged in user. Note that you could also use the `listPublished` method here instead
// of `cms.listLatestEntries`, if a list of published posts is what you need.
const response: [CmsEntry[], CmsEntryMeta] = await cms.listLatestEntries(model, {
where: {
// Retrieving the currently logged in user is as easy
// as calling the `security.getIdentity` method.
createdBy: security.getIdentity().id
}
});
return new ListResponse(...response);
}
}
}
})
];
The code above can be placed in the api/headlessCMS/src/plugins/posts.ts
file, which doesn’t exist by default, so you will have to create it manually. Furthermore, once the file is created, make sure that it’s actually imported and registered in the api/headlessCMS/src/index.ts
entrypoint file.
With all the changes in place, we should be able to run the following GraphQL mutation:
{
listPosts {
data {
title
text
}
}
listMyPosts {
data {
title
text
}
}
}
For example:
As we can see, the listPosts
query returned a total of three posts. On the other hand, the listMyPosts
only returned posts for the currently logged in user, which is the expected result.
FAQ
What Is the context
Object and Where Are All of Its Properties Coming From?
In the shown examples, you may have noticed we were using the context
object in GraphQL resolver functions. This object contains multiple different properties, mainly being defined from different Webiny applications that were imported in the Headless CMS GraphQL API’s api/headlessCMS/src/index.ts
entrypoint file.
That’s why, for example, we were able to utilize the cms.models.get
and cms.entries.listLatest
methods.
For easier discovery and type safety, we suggest a type is always assigned to the context
object in your GraphQL resolver functions.