GraphQL API
The GraphQL API is a read-only API for delivering content from Statamic to your frontend, external apps, SPAs, and numerous other possible sources. Content is delivered as JSON data.
(If you're interested in a REST API, we have one of those too.)
Enable GraphQL#
To enable the GraphQL API, add the following to your .env
file:
STATAMIC_GRAPHQL_ENABLED=trueenvenv
Or you can enable it for all environments in config/statamic/graphql.php
:
'enabled' => true,phpphp
You will also need to enable the resources you want to be available. For security, they're all disabled by default.
When GraphQL is enabled, GraphiQL is available in the Control Panel. This allows you to explore and test available queries and fields.

If you publish the underlying package's config, the query routes will be enabled regardless of whether you've disabled it in the Statamic config.

Enable resources#
You can enable resources (ie. Collections, Taxonomies, etc.) in your config/statamic/graphql.php
config:
'resources' => ['collections' => true,'taxonomies' => true,// etc.]phpphp
Enable specific sub-resources#
If you want more granular control over which sub-resources are enabled within a resource type (ie. enabling specific Collection queries only), you can use array syntax:
'resources' => ['collections' => ['articles' => true,'pages' => true,// 'events' => false, // Sub-resources are disabled by default],'taxonomies' => true,// etc.]phpphp
Interfaces#
Statamic will provide "interface" types, which describe more generic items. For instance, an EntryInterface
exists for all
entries, which would provide fields like id
, slug
, status
, title
, and so on.
In addition to the interfaces, Statamic will provide implementations of them, which would come from the blueprints.
For example, if you had a collection named pages
, and it had blueprints of page
and home
, you would find Entry_Pages_Page
and Entry_Pages_Home
types. These implementations would provide fields specific to the blueprint, like subtitle
, content
, etc.
{entries {idtitle... on Entry_Pages_Page {subtitlecontent}... on Entry_Pages_Home {hero_introhero_image}}}graphqlgraphql
Queries#
Statamic has a number of root level queries you can perform to get data.
You can read about the available queries further down the page,
but know that you can perform more than one query at a time. They just need to be at the top level of your GraphQL query body.
For example, the following would perform both entries
and collections
queries
{entries {# ...}collections {# ...}}graphqlgraphql
The response will contain the results of both queries:
{"entries": { /* ... */ },"collections": { /* ... */ },}jsonjson
Note that you can even perform the same query multiple times. If you want to do this, you should use aliases:
{home: entry(id: "home") {title}contact: entry(id: "contact") {title}}graphqlgraphql
{"home": { /* ... */ },"contact": { /* ... */ },}jsonjson
Available queries#
- Ping
- Collections
- Collection
- Entries
- Entry
- Asset Containers
- Asset Container
- Assets
- Asset
- Taxonomies
- Taxonomy
- Terms
- Term
- Global Sets
- Global Set
- Navs
- Nav
Ping#
Used for testing that your connection works. If you send a query of {ping}
, you should receive {"data": {"ping": "pong"}}
.
{ping}graphqlgraphql
{"data": {"ping": "pong"}}jsonjson
Collections#
Used for querying collections.
Returns a list of Collection types.
{collections {handletitle}}graphqlgraphql
{"collections": [{ "handle": "blog", "title": "Blog Posts" },{ "handle": "events", "title": "Events" },]}jsonjson
Collection#
Used for querying a single collection.
Returns a Collection type.
{collection(handle: "blog") {handletitle}}graphqlgraphql
{"collections": {"handle": "blog","title": "Blog Posts"}}jsonjson
Entries#
Used for querying multiple entries.
Returns a paginated list of EntryInterface types.
Argument | Type | Description |
---|---|---|
collection |
[String] |
Narrows down the results by entries in one or more collections. |
limit |
Int |
The number of results to be shown per paginated page. |
page |
Int |
The paginated page to be shown. Defaults to 1 . |
filter |
JsonArgument |
Narrows down the results based on filters. |
sort |
[String] |
Sorts the results based on one or more fields and directions. |
Example query and response:
{entries {current_pagedata {idtitle}}}graphqlgraphql
{"entries": {"current_page": 1,"data": [{ "id": 1, "title": "First Entry" },{ "id": 2, "title": "Second Entry" }]}}jsonjson
Entry#
Used for querying a single entry.
{entry(id: 1) {idtitle}}graphqlgraphql
{"entry": {"id": 1,"title": "First Entry"}}jsonjson
Asset containers#
Used for querying asset containers.
{assetContainers {handletitle}}graphqlgraphql
{"assetContainers": [{ "handle": "images", "title": "Images" },{ "handle": "documents", "title": "Documents" },]}jsonjson
Asset container#
Used for querying a single asset container.
Returns an AssetContainer type.
{assetContainer(handle: "images") {handletitle}}graphqlgraphql
{"assetContainer": {"handle": "images","title": "Images"}}jsonjson
Argument | Type | Description |
---|---|---|
handle |
String! |
Specifies which asset container to retrieve. |
Assets#
Used for querying multiple assets of an asset container.
Returns a paginated list of AssetInterface types.
Argument | Type | Description |
---|---|---|
container |
String! |
Specifies which asset container to query. |
limit |
Int |
The number of results to be shown per paginated page. |
page |
Int |
The paginated page to be shown. Defaults to 1 . |
filter |
JsonArgument |
Narrows down the results based on filters. |
sort |
[String] |
Sorts the results based on one or more fields and directions. |
Example query and response:
{assets(container: "images") {current_pagedata {url}}}graphqlgraphql
{"entries": {"current_page": 1,"data": [{ "url": "/assets/images/001.jpg" },{ "url": "/assets/images/002.jpg" },]}}jsonjson
Asset#
Used for querying a single asset.
{asset(id: 1) {idtitle}}graphqlgraphql
{"asset": {"id": 1,"title": "First Entry"}}jsonjson
You can either query by id
, or by container
and path
together.
Argument | Type | Description |
---|---|---|
id |
String |
The ID of the asset. If you use this, you don't need container or path . |
container |
String |
The container to look for the asset. You must also provide the path . |
path |
String |
The path to the asset, relative to the container. You must also provide the container . |
Taxonomies#
Used for querying taxonomies.
{taxonomies {handletitle}}graphqlgraphql
{"taxonomies": [{ "handle": "tags", "title": "Tags" },{ "handle": "categories", "title": "Categories" },]}jsonjson
Taxonomy#
Used for querying a single taxonomy.
{taxonomy(handle: "tags") {handletitle}}graphqlgraphql
{"taxonomy": {"handle": "tags","title": "Tags"}}jsonjson
Terms#
Used for querying multiple taxonomy terms.
Returns a paginated list of TermInterface types.
Argument | Type | Description |
---|---|---|
taxonomy |
[String] |
Narrows down the results by terms in one or more taxonomies. |
limit |
Int |
The number of results to be shown per paginated page. |
page |
Int |
The paginated page to be shown. Defaults to 1 . |
filter |
JsonArgument |
Narrows down the results based on filters. |
sort |
[String] |
Sorts the results based on one or more fields and directions. |
Example query and response:
{terms {current_pagedata {idtitle}}}graphqlgraphql
{"terms": {"current_page": 1,"data": [{ "id": "tags::one", "title": "Tag One" },{ "id": "tags::two", "title": "Tag Two" }]}}jsonjson
Term#
Used for querying a single taxonomy term.
{term(id: "tags::one") {idtitle}}graphqlgraphql
{"term": {"id": "tags::one","title": "Tag One"}}jsonjson
Global sets#
Used for querying multiple global sets.
Returns a list of GlobalSetInterface types.
Argument | Type | Description |
---|---|---|
taxonomy |
[String] |
Narrows down the results by terms in one or more taxonomies. |
limit |
Int |
The number of results to be shown per paginated page. |
page |
Int |
The paginated page to be shown. Defaults to 1 . |
sort |
[String] |
Sorts the results based on one or more fields and directions. |
Example query and response:
{globalSets {titlehandle... on GlobalSet_Social {}... on GlobalSet_Company {company_name}}}graphqlgraphql
{"globalSets": [{ "handle": "social", "twitter": "@statamic" },{ "handle": "company", "company_name": "Statamic" },]}jsonjson
Global set#
Used for querying a single global set.
{globalSet(handle: "social") {titlehandle... on GlobalSet_Social {}}}graphqlgraphql
{"globalSet": {"title": "Social","handle": "social","twitter": "@statamic",}}jsonjson
Forms#
Used for querying multiple forms.
{forms {handletitlefields {handledisplay}}}graphqlgraphql
{"forms": [{"handle": "contact","title": "Contact","fields": [{ "handle": "name", "display": "Name" },{ "handle": "email", "display": "Email" },{ "handle": "inquiry", "display": "Inquiry" }]}]}jsonjson
Form#
Used for querying a single form.
{form(handle: "contact") {handletitlefields {handledisplay}}}graphqlgraphql
{"form": {"handle": "contact","title": "Contact","fields": [{ "handle": "name", "display": "Name" },{ "handle": "email", "display": "Email" },{ "handle": "inquiry", "display": "Inquiry" }]}}jsonjson
Navs#
Used for querying Navs.
{navs {handletitle}}graphqlgraphql
{"navs": [{ "handle": "header_links", "title": "Header Links" },{ "handle": "footer_links", "title": "Footer Links" },]}jsonjson
Nav#
Used for querying a single Nav.
{nav(handle: "footer") {handletitle}}graphqlgraphql
{"nav": {"handle": "footer","title": "Footer Links"}}jsonjson
Users#
Used for querying multiple users.
Argument | Type | Description |
---|---|---|
limit |
Int |
The number of results to be shown per paginated page. |
page |
Int |
The paginated page to be shown. Defaults to 1 . |
filter |
JsonArgument |
Narrows down the results based on filters. |
sort |
[String] |
Sorts the results based on one or more fields and directions. |
Example query and response:
{users {current_pagedata {name}}}graphqlgraphql
{"users": {"current_page": 1,"data": [{ "name": "David Hasselhoff", "email": "thehoff@statamic.com" },{ "name": "Chuck Norris", "email": "norris@statamic.com" },]}}jsonjson
User#
Used for querying a single user.
{user(email: "thehoff@statamic.com") {name}}graphqlgraphql
{"user": {"name": "David Hasselhoff","email": "thehoff@statamic.com"}}jsonjson
You can query by either id
or email
.
Argument | Type | Description |
---|---|---|
id |
String |
The ID of the user. If you use this, you don't email . |
email |
String |
The email address of the user. If you use this, you don't id . |
Custom queries#
Here's an example of a basic query class. It has the name attribute which is the key the user needs to put in the request, any number of middleware, the type(s) that will be returned, any arguments, and how the data should be resolved.
use Statamic\Facades\GraphQL;use Statamic\GraphQL\Queries\Query;class Products extends Query{protected $attributes = ['name' => 'products',];protected $middleware = [MyMiddleware::class,];public function type(): Type{return GraphQL::paginate(GraphQL::type(ProductType::NAME));}public function args(): array{return ['limit' => GraphQL::int(),];}public function resolve($root, $args){return Product::paginate($args['limit']);}}phpphp
{products {nameprice}}graphqlgraphql
You may add your own queries to Statamic's default schema.
You can add them to the config file, which makes sense for app specific queries:
// config/statamic/graphql.php'queries' => [MyCustomQuery::class]phpphp
Or, you may use the addQuery
method on the facade, which would be useful for addons.
GraphQL::addQuery(MyCustomQuery::class);phpphp
Types#
- EntryInterface
- Collection
- CollectionStructure
- CollectionTreeBranch
- NavTreeBranch
- PageInterface
- TermInterface
- AssetInterface
- GlobalSetInterface
- Code
EntryInterface#
Field | Type | Description |
---|---|---|
id |
ID! |
|
title |
String! |
Each EntryInterface
will also have implementations for each collection/blueprint combination.
You will need to query the implementations using fragments in order to get blueprint-specific fields.
{entries {idtitle... on Entry_Blog_Post {introcontent}... on Entry_Blog_ArtDirected_Post {hero_imagecontent}}}graphqlgraphql
The fieldtypes will define their types. For instance, a text field will be a String
, a grid field will expose a list of GridItem
types.
Collection#
Field | Type | Description |
---|---|---|
handle |
String! |
|
title |
String! |
|
structure |
CollectionStructure |
If the collection is structured (e.g. a "pages" collection), you can use this to query its tree. |
CollectionStructure#
Field | Type | Description |
---|---|---|
handle |
String! |
|
title |
String! |
|
tree |
[CollectionTreeBranch ] |
A list of tree branches. |
CollectionTreeBranch#
Represents a branch within a structured collection's tree.
Field | Type | Description |
---|---|---|
depth |
Int! |
The nesting level of the current branch. |
entry (or page ) |
EntryInterface |
Contains the entry's fields. |
children |
[CollectionTreeBranch ] |
A list of tree branches. |
It's not possible to perform recursive queries in GraphQL. If you want to retrieve multiple levels of child branches, take a look at a workaround in recursive tree branches below.

NavTreeBranch#
Represents a branch within a nav's tree.
Field | Type | Description |
---|---|---|
depth |
Int! |
The nesting level of the current branch. |
page |
PageInterface |
Contains the page's fields. |
children |
[NavTreeBranch ] |
A list of tree branches. |
It's not possible to perform recursive queries in GraphQL. If you want to retrieve multiple levels of child branches, take a look at a workaround in recursive tree branches below.

PageInterface#
A "page" within a nav's tree.
Field | Type | Description |
---|---|---|
id |
ID! |
The ID of the page. |
entry_id |
ID |
The entry ID. |
title |
String |
For entry pages, it's the entry's title unless overridden on the branch. For basic pages, it's the title . |
url |
String |
For entry pages, it's the entry's url . For basic pages, it's the url . For text-only pages it'll be null. |
permalink |
String |
The absolute version of url . |
If you want to query any fields that you've added to the nav's blueprint, you have 4 different options available to you that you can use as inline fragments.
You can use more than one at a time:
EntryInterface
for all entry pages.NavEntryPage_{NavHandle}_{Collection}_{Blueprint}
for a specific entry/blueprint combination on entry pages.NavBasicPage_{NavHandle}
for basic non-entry pages.NavPage_{NavHandle}
for either basic or entry pages.
page {titleurl... on EntryInterface {# ...}... on NavPage_HeaderLinks {# ...}... on NavBasicPage_HeaderLinks {# ...}... on NavEntryPage_HeaderLinks_Blog_ArtDirected {# ...}}graphqlgraphql
TermInterface#
Field | Type | Description |
---|---|---|
id |
ID! |
|
title |
String! |
|
slug |
String! |
Each TermInterface
will also have implementations for each taxonomy/blueprint combination.
You will need to query the implementations using fragments in order to get blueprint-specific fields.
{terms {idtitle... on Term_Tags_RegularTag {content}... on Term_Tags_SpecialTag {how_specialcontent}}}graphqlgraphql
The fieldtypes will define their types. For instance, a text field will be a String
, a grid field will expose a list of GridItem
types.
AssetInterface#
Field | Type | Description |
---|---|---|
path |
String! |
The path to the asset. |
Each AssetInterface
will also have an implementation for each asset container's blueprint.
You will need to query the implementations using fragments in order to get blueprint-specific fields.
{entries {path... on Asset_Images {alt}}}graphqlgraphql
The fieldtypes will define their types. For instance, a text field will be a String
, a grid field will expose a list of GridItem
types.
GlobalSetInterface#
Field | Type | Description |
---|---|---|
handle |
String! |
The handle of the set. |
title |
String! |
The title of the set. |
Each GlobalSetInterface
will also have an implementation for each set's blueprint.
While Statamic doesn't enforce a blueprint for globals (see Blueprint is Optional), it is required within the GraphQL context. Fields that haven't been explicitly added to a blueprint will not be available.

You will need to query the implementations using fragments in order to get blueprint-specific fields.
{globalSets {handle... on GlobalSet_Social {}}}graphqlgraphql
The fieldtypes will define their types. For instance, a text field will be a String
, a grid field will expose a list of GridItem
types.
Code#
Field | Type | Description |
---|---|---|
code |
String! |
The actual code value. |
mode |
String! |
The language "mode". |
The code fieldtype will return this type when mode_selectable
is enabled. Otherwise, it'll just be a string.
{snippet {codemode}}graphqlgraphql
Filtering#
Enabling filters#
For security, filtering is disabled by default. To enable, you'll need to opt in by defining a list of allowed_filters
for each sub-resource in your config/statamic/graphql.php
config:
'resources' => ['collections' => ['articles' => ['allowed_filters' => ['title', 'status'],],'pages' => ['allowed_filters' => ['title'],],'events' => true, // Enable this collection without filters'products' => true, // Enable this collection without filters],'taxonomies' => ['topics' => ['allowed_filters' => ['slug'],],'tags' => true, // Enable this taxonomy without filters],// etc.],phpphp
For queries that don't have sub-resources (ie. users), you can define allowed_filters
at the top level of that resource config:
'resources' => ['users' => ['allowed_filters' => ['name', 'email'],],],phpphp
Using filters#
You can filter the results of listing queries (like entries
) using the filter
argument. This argument accepts a JSON object containing different
conditions.
{entries(filter: {title: { contains: "rad", ends_with: "!" }}) {data {title}}}graphqlgraphql
{"data": [{ "title": "That was so rad!" },{ "title": "I wish I was as cool as Daniel Radcliffe!" },]}jsonjson
If you only need to do a simple "equals" condition, then you can use a string and omit the condition name, like the rating
here:
{entries(filter: {title: { contains: "rad" }rating: 5}) {# ...}graphqlgraphql
If you need to use the same condition on the same field more than once, you can use the array syntax:
{entries(filter: {title: [{ contains: "rad" },{ contains: "awesome" },]}) {# ...}graphqlgraphql
Advanced filtering config#
You can also allow filters on all enabled sub-resources using a *
wildcard config. For example, here we'll enable only the articles
, pages
, and products
collections, with title
filtering enabled on each, in addition to status
filtering on the articles
collection specifically:
'resources' => ['collections' => ['*' => ['allowed_filters' => ['title'], // Enabled for all collections],'articles' => ['allowed_filters' => ['status'], // Also enable on articles],'pages' => true,'products' => true,],],phpphp
If you've enabled filters using the *
wildcard config, you can disable filters on a specific sub-resource by setting allowed_filters
to false
:
'resources' => ['collections' => ['*' => ['allowed_filters' => ['title'], // Enabled for all collections],'articles' => ['allowed_filters' => false, // Disable filters on articles],'pages' => true,'products' => true,],],phpphp
Or you can enable queries and filters on all sub-resources at once by setting both enabled
and allowed_filters
within your *
wildcard config:
'resources' => ['collections' => ['*' => ['enabled' => true, // All collection queries enabled'allowed_filters' => ['title'], // With filters enabled for all],],],phpphp
Sorting#
You can sort the results of listing queries (like entries
) on one or multiple fields, in any direction.
{entries(sort: "title") {# ...}graphqlgraphql
{entries(sort: "title desc") {# ...}graphqlgraphql
{entries(sort: ["price desc", "title asc"]) {# ...}graphqlgraphql
Pagination#
Some queries (like entries) will provide their results using pagination.
In a paginated response, you will find the actual items within a data
key.
By default there will be 1000
per page. You can change this using a limit
argument.
You can specify the current paginated page using the page
argument.
{entries(limit: 15, page: 2) {current_pagehas_more_pagesdata {# ...}}}graphqlgraphql
Field | Type | Description |
---|---|---|
data |
[mixed] | A list of items on the current page. In an entries query, there will be EntryInterface types, etc. |
total |
Int! |
Number of total items selected by the query. |
per_page |
Int! |
Number of items returned per page. |
current_page |
Int! |
Current page of the cursor. |
from |
Int |
Number of the first item returned. |
to |
Int |
Number of the last item returned. |
last_page |
Int! |
The last page (number of pages). |
has_more_pages |
Boolean! |
Determines if cursor has more pages after the current page. |
Fieldtypes#
Replicator#
Replicator fields require that you query each set using a separate fragment.
The fragments are named after your configured sets using StudlyCased field and set handles. e.g. Set_{ReplicatorFieldName}_{SetHandle}
fields:-handle: content_blocksfield:type: replicatorsets:image:fields:-handle: imagetype: assetsmax_files: 1pull_quote:fields:-handle: quotefield:type: textarea-handle: authorfield:type: textyamlyaml
{content_blocks {... on Set_ContentBlocks_Image {typeimage}... on Set_ContentBlocks_PullQuote {typequoteauthor}}}graphqlgraphql
If you have nested fields, include each parent's handle, (and grandparent's, great grandparent's etc), like so: Set_TopLevelReplicator_NestedReplicator_DeeplyNestedReplicator_SetHandle

Bard#
Bard fields work the same as Replicator, except that you also have an additional BardText
for the text fragment.
{content_blocks {... on BardText {typetext}... on Set_ContentBlocks_Image {typeimage}... on Set_ContentBlocks_PullQuote {typequoteauthor}}}graphqlgraphql
Grid#
Grid fields can be queried with no extra requirements. You can just use the nested field handles.
{cars {makemodel}}graphqlgraphql
Select, radio, checkboxes, and button group#
These fieldtypes provide you with labels and values. You'll need to use a sub selection.
my_select_field {valuelabel}graphqlgraphql
"my_single_select_field": {"value": "potato","label": "Potato"}jsonjson
The same syntax is used when multiple values are expected. e.g. a select field with multiple values enabled, or a checkboxes field. You'll just get a nested array returned.
"my_multi_select_field": [{"value": "potato","label": "Potato"},{"value": "tomato","label": "Tomato",}]jsonjson
Recursive tree branches#
Often, when dealing with navs, you need to recursively output all the child branches. For example, when using the nav
tag in Antlers, you might do something like this:
<ul>{{ nav }}<li><a href="{{ url }}">{{ title }}</a>{{ if children }}<ul>{{ *recursive children* }}</ul>{{ /if }}</li>{{ /nav }}</ul>antlersantlers
In GraphQL, it's not possible to perform recursive queries like that. You'll need to explicitly query each level:
{nav(handle: "links") {tree {page {titleurl}children {page {titleurl}children {page {titleurl}}}}}}graphqlgraphql
In this example, if you wanted anything more than title
and url
, you'd need to add them to each level.
This can quickly become tedious and is very repetitive, so here's a workaround using fragments.
If you wanted to add more fields, you only need to do it one spot - the Fields
fragment. If you want to query more levels, you can just increase the nesting level of the RecursiveChildren
fragment.
{nav(handle: "links") {tree {...Fields...RecursiveChildren}}}fragment Fields on NavTreeBranch {depthpage {titleurl# any other fields you want for each branch}}fragment RecursiveChildren on NavTreeBranch {children {...Fieldschildren {...Fieldschildren {...Fields# just keep repeating this as deep as necessary}}}}graphqlgraphql
Hat tip to Hash Interactive for their blog post on this technique.
Custom fieldtypes#
A fieldtype can define what GraphQL type will be used. By default, all fieldtypes will return strings.
use GraphQL\Type\Definition\Type;public function toGqlType(){return GraphQL::string();}phpphp
You're free to return an array with a more complicated structure in order to provide arguments, etc.
use GraphQL\Type\Definition\Type;public function toGqlType(){return ['type' => GraphQL::string(),'args' => [//]];}phpphp
If you need to register any types, the fieldtype can do that in the addGqlTypes
method:
public function addGqlTypes(){// A class that extends Rebing\GraphQL\Support\Type$type = MyType::class; // or `new MyType;`GraphQL::addType($type);}phpphp
Laravel package#
Under the hood, Statamic uses the rebing/graphql-laravel package.
By default, the integration should feel seamless and you won't even know another package is being used. Statamic will perform the following automatic configuration of this package:
- Setting up the
default
schema to Statamic's. - Disabling the
/graphiql
route (since we have our own inside the Control Panel)
However, you're free to use this package on its own, as if you've installed it into a standalone Laravel application.
If Statamic detects that you've published the package's config file (located at config/graphql.php
), it will assume you're trying to use it manually and will
avoid doing the automatic setup steps mentioned above.
If you'd like to use Statamic's GraphQL schema within the config file (maybe you want a different default, and want Statamic's one at /graphql/statamic
) you can use the DefaultSchema
class.
['schemas' => ['statamic' => \Statamic\GraphQL\DefaultSchema::class]]phpphp
Authorization#
By default, all queries are allowed by anyone. We plan to add native features in the future.
You can define custom authorization logic for any query by providing a closure to the static auth
method.
EntriesQuery::auth(function () {return true; // true authorizes, false denies.});phpphp
Custom fields#
You can add fields to certain types by using the addField
method on the facade.
The method expects the type name, the field name, and a closure that returns a GraphQL field definition array.
For example, if you wanted to include a thumbnail from an asset field named image
, you could do that here. You can even have arguments. In this example, we'll expect the width of the thumbnail to be passed in.
use GraphQL\Type\Definition\Type;use Statamic\Facades\GraphQL;use Statamic\Facades\Image;use Statamic\Facades\URL;GraphQL::addField('EntryInterface', 'thumbnail', function () {return ['type' => GraphQL::string(),'args' => ['width' => ['type' => GraphQL::int(),]],'resolve' => function ($entry, $args) {$asset = $entry->image;$url = Image::manipulate($asset)->width($args['width'])->build();return URL::makeAbsolute($url);}];});phpphp
{entry(id: 1) {thumbnail(width: 100)}}graphqlgraphql
{"entry": {"thumbnail": "http://yoursite.com/img/asset/abc123?w=100"}}jsonjson
The closure you pass to the method should return a GraphQL field definition array.
You may add custom fields to the following types and any of their implementations:
EntryInterface
PageInterface
TermInterface
AssetInterface
GlobalSetInterface
Caching#
GraphQL uses a basic whole-response cache by default. Each query/variables combination's response will be cached for an hour. You may customize the cache expiry in config/statamic/graphql.php
.
'cache' => ['expiry' => 60,],phpphp
Cache invalidation#
Cached responses are automatically invalidated when content is changed. Depending on your GraphQL usage and blueprint schema, you may also wish to ignore specific events when invalidating.
'cache' => ['expiry' => 60,'ignored_events' => [\Statamic\Events\UserSaved::class,\Statamic\Events\UserDeleted::class,],],phpphp
Disabling caching#
If you wish to disable caching altogether, set cache
to false
.
'cache' => false,phpphp
Custom middleware#
You may add custom middleware, which are identical to any other Laravel middleware class. They will be executed on all GraphQL requests (unless another middleware, e.g. caching, prevents it).
Use the handle
method to perform some action, and pass the request on.
use Closure;class MyMiddleware{public function handle($request, Closure $next){// do somethingreturn $next($request);}}phpphp
You may add your own middleware to Statamic's default schema.
You can add them to the config file, which makes sense for app specific middleware:
// config/statamic/graphql.php'middleware' => [MyMiddleware::class]phpphp
Or, you may use the addMiddleware
method on the facade, which would be useful for addons.
GraphQL::addMiddleware(MyMiddleware::class);phpphp
Troubleshooting#
"Cannot query field" error#
If you see an error like Cannot query field "entries" on type "Query"
, this likely means you haven't enabled that query. See Enable GraphQL.
After enabling it, you may need to clear your cache as the request would probably have been cached.
Docs Feedback
Submit improvements, related content, or suggestions through Github.
Betterify this page