Skip to main content

Extending the GraphQL schema

Although the FastStore API provides a complete GraphQL schema for ecommerce, some stores may need to access other, more specific, information.

For those cases, it is possible to extend the FastStore API schema, adding new data to the existing queries.

info

Once you have implemented the schema extension in your code, you can run a local test with GraphiQL.

Implementationโ€‹

To do this, there are a few steps you must follow:

  1. Prepare files.
  2. Create type definitions.
  3. Create resolvers.
  4. Get FastStore API schema.
  5. Merge executable schemas.

Prepare filesโ€‹

The FastStore executable schema is exported by the src/server/intex.ts file of your project. This means you must edit that same file to merge the existing schema with the one you create.

However, you have the option of creating other folders and files to organize your new type definitions and resolvers. This may be a good idea, especially if you wish to add a large number of new fields to the schema.

Importing toolsโ€‹

Once you decided on your file structure, you can import the tools necessary to manipulate the schemas:

import { getSchema, getTypeDefs } from '@faststore/api'
import { makeExecutableSchema, mergeSchemas } from '@graphql-tools/schema'
import { mergeTypeDefs } from '@graphql-tools/merge'
import type { Options as APIOptions } from '@faststore/api'

Create type definitionsโ€‹

Your new type definitions set the data structure for your new fields, extended from the existing FastStore GraphQL queries and types.

See the following code example of adding a new field called customField, which is a string, to the existing type StoreProduct.

const typeDefs = `
extend type StoreProduct {
customField: String
}
`

Create resolversโ€‹

Resolvers are the functions that give meaning to the data you have structured in the type definitions. This means a resolver will be executed when the corresponding piece of information is queried.

A resolver can perform an operation on an existing field or fetch data from a proprietary API, for example.

You can create your resolvers like in the following code example.

const resolvers = {
StoreProduct: {
customField: async () => {
...
// Your code goes here
...
}
}
}

It is important to note that every resolver has implicit arguments aside from what you define when writing your function. This includes the root of the type, which means your resolver has access to all information in that type.

For instance, in the example above the resolver can use whatever information is contained in the existing StoreProduct type definition.

Get FastStore API schemaโ€‹

To get the existing FastStore API schema, use the imported getSchema function. This function takes arguments in the form of the imported APIOptions type.

It is likely that your src/server/index.ts file already has this implemented like in the example below.

import { getSchema } from '@faststore/api'
import type { Options as APIOptions } from '@faststore/api'

...

const apiOptions: APIOptions = {
platform: storeConfig.platform as APIOptions['platform'],
account: storeConfig.api.storeId,
environment: storeConfig.api.environment as APIOptions['environment'],
hideUnavailableItems: storeConfig.api.hideUnavailableItems,
channel: storeConfig.session.channel,
locale: storeConfig.session.locale,
flags: {
enableOrderFormSync: true,
},
}

export const apiSchema = getSchema(apiOptions)

Merge executable schemasโ€‹

Now it is time to make an executable schema from your newly created type definitions and resolvers and then merge that with the existing FastStore API schema.

To do this, use the imported functions makeExecutableSchema and mergeSchemas like in the example below.

import { getTypeDefs } from '@faststore/api'
import { makeExecutableSchema, mergeSchemas } from '@graphql-tools/schema'
import { mergeTypeDefs } from '@graphql-tools/merge'

...

// Merging your custom type definitions with the ones from @faststore/api
const mergedTypeDefs = mergeTypeDefs([getTypeDefs(), typeDefs])

const getMergedSchemas = async () =>
mergeSchemas({
schemas: [
await apiSchema,
makeExecutableSchema({
resolvers,
typeDefs: mergedTypeDefs,
}),
],
resolvers,
})

// Merging schemas into a final schema
export const finalSchema = getMergedSchemas()
caution

Note that the final merged schema in the example above has a different name than the existing exported one. You must make sure that all instances in which it is used have the correct name. You can see an example of how to do this in the complete example below.

Complete implementation exampleโ€‹

The example below contains all code described in the sections above as it might be implemented in a single file, src/server/index.ts.

info

As indicated above, this example contains adjusted schema names, so as not to break anything previously using the exported schema.

import { getSchema, getTypeDefs } from '@faststore/api'
import { makeExecutableSchema, mergeSchemas } from '@graphql-tools/schema'
import { mergeTypeDefs } from '@graphql-tools/merge'
import type { Options as APIOptions } from '@faststore/api'

...

// Creating type definitions
const typeDefs = `
extend type StoreProduct {
customField: String
}
`

// Creating resolvers
const resolvers = {
StoreProduct: {
customField: async () => {
...
// Your code goes here
...
}
}
}

// Getting existing FastStore API schema
const apiOptions: APIOptions = {
platform: storeConfig.platform as APIOptions['platform'],
account: storeConfig.api.storeId,
environment: storeConfig.api.environment as APIOptions['environment'],
hideUnavailableItems: storeConfig.api.hideUnavailableItems,
channel: storeConfig.session.channel,
locale: storeConfig.session.locale,
flags: {
enableOrderFormSync: true,
},
}

const nativeApiSchema = getSchema(apiOptions)

// Merging your custom type definitions with the ones from @faststore/api
const mergedTypeDefs = mergeTypeDefs([getTypeDefs(), typeDefs])

const getMergedSchemas = async () =>
mergeSchemas({
schemas: [
await nativeApiSchema,
makeExecutableSchema({
resolvers,
typeDefs: mergedTypeDefs,
}),
],
resolvers,
})

// Merging schemas into a final schema
export const apiSchema = getMergedSchemas()

Didn't find your answers? Ask the Community. For documentation suggestions, submit your feedback.

JOIN THE COMMUNITY