JSON Schema or Samples

This handler allows you to load any remote REST service and describe its request/response using the YAML config.

You can easily customize and control the built GraphQL schema with this handler.

How to use?

To get started, install the handler library:

npm i @omnigraph/json-schema

Now, you can use it directly in your Mesh config file:

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'users',
            path: '/users',
            method: 'GET',
            responseSchema: './json-schemas/users.json'
          }
        ]
      })
    }
  ]
})

Headers

Read about configuration and examples

From Arguments

Mesh automatically generates arguments for operations if needed;

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'user',
            path: '/user/{args.id}',
            method: 'GET',
            responseSchema: './json-schemas/user.json'
          }
        ]
      })
    }
  ]
})

This example operation definition will generate a root field with id: ID argument. Mesh will interpolate the expression in path to get id value from args.

From JSON Samples

Mesh can also load JSON samples from a remote service. Add a json-samples directory in your project root, and put the JSON samples there (responseSample: './jsons/MyField.response.json' - Create a new folder like jsons). By declaring the responseSample, you can use the JSON sample in the GraphQL schema.

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'myField',
            path: '/myField?id={args.id}',
            method: 'GET',
            responseSample: './jsons/MyField.response.json',
            responseTypeName: 'MyResponseName',
            argTypeMap: {
              id: {
                type: 'string'
              }
            }
          }
        ]
      })
    }
  ]
})
MyField.response.json
Any JSON sample file can be used.

Query Parameters

There are a few methods to define the query parameters, select the one that fits your needs (Or combine them):

Auto declare:

Mesh automatically generates arguments for operations if needed. Note that the arguments are generated as nullable strings by default.

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'user',
            path: '/user?id={args.id}',
            method: 'GET',
            responseSchema: './json-schemas/user.json'
          }
        ]
      })
    }
  ]
})

With Samples

You can use the JSON samples to define the query parameters.

In this example we declare limit and offset properties:

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'getUsers',
            path: '/users',
            method: 'GET',
            queryParamsSample: './jsons/users.queryParams.json',
            responseSchema: './jsons/users.response.json'
          }
        ]
      })
    }
  ]
})

In ./jsons/users.queryParams.json:

users.queryParams.json
{
  "limit": 10,
  "offset": 0
}

Manual Declare

You can define the arguments of the operation using the argTypeMap config field, according to the JSON Schema spec.

type: number will set the property to Float and type: integer will set it as Int.

In this example we declare page argument as an object with limit and offset properties:

argTypeMap: {
  page: {
    type: 'object',
    properties: {
      limit: {
        type: 'integer'
      },
      offset: {
        type: 'integer'
      }
    }
  }
}

Array can be defined as type: array with items: and their own type:

argTypeMap: {
  page: {
    type: 'array',
    items: {
      limit: {
        type: 'integer'
      },
      offset: {
        type: 'integer'
      }
    }
  }
}

If you need to use symbols that will cause GraphQL to error like ’:’ or ’[’ in the query param name, you can map an alternative definition. With the below example using name_like in the query will end up being name:like as the API call.

argTypeMap: {
  name_like: {
    type: 'string'
  }
  queryParamArgMap: {
    'name:like': 'name_like'
  }
}

In addition, especially for non-primitive types, the arguments should be added to the path using the queryParamArgMap config field.

Here we add the page argument to the query parameters:

queryParamArgMap: {
  page: 'page'
}

And here is the final config:

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'getUsers',
            path: '/users',
            method: 'GET',
            responseSample: './jsons/users.response.json',
            responseTypeName: 'MyResponseName',
            argTypeMap: {
              page: {
                type: 'object',
                properties: {
                  limit: {
                    type: 'integer'
                  },
                  offset: {
                    type: 'integer'
                  }
                }
              }
            },
            queryParamArgMap: {
              page: 'page'
            }
          }
        ]
      })
    }
  ]
})

Global Arguments

Query arguments could be defined globally, on handler level, so they are added to all operations.

In this example we declare limit parameter with the default value of 10, and api_key with dynamic value taken from the environment:

mesh.config.ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'
 
export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          // Operations here
        ],
        queryParams: {
          limit: 10,
          api_key: '{env.MY_API_KEY}'
        }
      })
    }
  ]
})
💡

Note that queryParams are automatically added to the query. If argument is defined both on handler AND operation level, the operation level argument will be used.