Migrate to GraphQL Mesh v1
OpenAPI / Swagger
This handler allows you to load remote or local OpenAPI (2/3) and Swagger schemas. This work originated from IBM Research, and is currently maintained by GraphQL Mesh.
For migrating from version < 0.32
see migration guide
You can import it using remote/local .json
or .yaml
.
To get started, install the handler library:
npm i @graphql-mesh/openapi
Now, you can use it directly in your Mesh config file / URL:
sources:
- name: MyOpenapiApi
handler:
openapi:
source: ./my-schema.json
Note that this handler is based on the JSON Schema handler - so it’s configurations will apply here as well.
Overriding default Query/Mutation operations classification
By default, all GET operations will be placed into Query fields and all other operations into Mutation fields. with this option, you can manually override this process. To switch between Query and Mutation operations, and vice versa, you need to define a rule per override, consisting of the OAS title, the path of the operation, the method of the operation and finally, the destination type (e.g., Query or Mutation). See the example below:
sources:
- name: MyOpenapiApi
handler:
openapi:
source: ./my-schema.json
selectQueryOrMutationField:
- fieldName: 'add_weather_forecast' # OAS field name
type: Query # switch method POST from default Mutation into Query
- fieldName: 'get_weather_forecast' # OAS field name
type: Mutation # switch method GET from default Query into Mutation
Naming convention
We use operationId
for the names, and aim to keep it as close as possible to origin.
Type naming
We adjust operationId
only when necessary according to the GraphQL spec: - Chars
(white
space), .
, /
, :
and -
are replaced with _
(underscore) - Other chars which are not
latin/digits are replaced with their char codes - If first char of the name is a digit, we prefix it
with _
(GraphQL spec doesn’t allow that)
Unnamed types
We use path-based naming. So names could be structured like, for example,
query_getUsers_items_firstName
Headers
Read about configuration and examples
Advanced cookies handling
When building a web application, cookies are often used for authentication for security reasons. On the other end, mobile applications tend to use an HTTP header.
This section shows how to configure GraphQL Mesh to accept either and use GraphQL Mesh to set/unset cookies on the login & logout mutations.
Accepting one of the cookies, header, or context value
We want to accept one of the following:
- an
accessToken
cookie - an
Authorization
header - an authorization value available in context (e.g. set by a GraphQL auth plugin)
And transmit it to the Rest API as an Authorization
header. GraphQL Mesh does not allow dynamic
selection in the meshrc.yaml
file, but that’s fine! We can use a bit of trickery.
sources:
- name: Rest
handler:
openapi:
source: ./openapi.yaml
endpoint: '{env.REST_URL}/api/'
operationHeaders:
Authorization-Header: '{context.headers.authorization}'
Authorization-Cookie: Bearer {context.cookies.accessToken}
# You can provide a custom fetch function to override the default fetch function
customFetch: ./src/custom-fetch.ts
Here in the meshrc.yaml
configuration we store the cookie in Authorization-Cookie
, and the
header in Authorization-Header
. To introduce the logic needed to generate the proper
Authorization
header for the Rest API, we need to implement a customFetch
. It will replace the
fetch
used by GraphQL Mesh to call the Rest API.
import { MeshContext } from '@graphql-mesh/runtime'
import { fetch } from '@whatwg-node/fetch'
export default function (
url: string,
options: RequestInit = {},
context?: MeshContext,
info?: GraphQLResolveInfo
) {
// Set Authorization header dynamically to context value, or input cookie, or input header, or from context.headers
options.headers['authorization'] =
context.authorization ||
options.headers['authorization-cookie'] ||
options.headers['authorization-header']
// Clean up headers forwarded to the Rest API
delete options.headers['authorization-cookie']
delete options.headers['authorization-header']
// Execute the fetch with the new headers
return fetch(url, options)
}
Setting / Unsetting the cookie
Of course, using GraphQL Mesh as a Gateway for both the mobile application and web application is excellent. Still, there’s one thing missing: the setting of the cookie for the web application.
We need to access the HTTP response that is sent back to the client. Luckily, we can do so in
additionalResolvers
. So we need to create two new resolvers, one for login and one for logout, and
manage the cookie in their code.
The first step is to edit the meshrc.yaml
file, add this at the end:
additionalTypeDefs: |
extend type Mutation {
login(credentials: Credentials!): String
logout: Boolean
}
additionalResolvers:
- ./src/additional-resolvers.js
Then manage the cookie in the new resolvers:
// lifespan of our cookie
const oneYear = 365 * 24 * 3600
const resolvers = {
Mutation: {
async login(root, args, context, info) {
// Call the Rest API's login operation
const result = await context.Rest.Mutation.accountLogin({
root,
args: {
credentials: args.credentials
},
context,
info
})
// if `result` contains a JWT token, you could instead decode it and set `Expires`
// to the JWT token's expiration date
context.res.set(
'Set-Cookie',
`accessToken=${result}; Path=/; Secure; HttpOnly; Max-Age=${oneYear};`
)
return result
},
logout(root, args, { res }) {
// use old date to unset cookie
res.set(
'Set-Cookie',
`accessToken=logout; Path=/; Secure; HttpOnly; Expires=Thu, 1 Jan 1970 00:00:00 GMT;`
)
return true
}
}
}
module.exports = { resolvers }
Callbacks as Subscriptions
OpenAPI handler is able to process OAS Callbacks as GraphQL Subscriptions. It uses your PubSub implementation to consume the data. But you have to define webhooks for individual callbacks to make it work.
See Subscriptions & Webhooks to create an endpoint to consume
a webhook. You should use the callback url as pubSubTopic
in the webhook configuration.
Also see our example; Subscriptions Example with Webhooks.
Loading the sources from a CDN like GraphQL Hive or schema registry
GraphQL Mesh supports loading the sources from a CDN or schema registry. You can use the source
property to load the schema from a CDN or schema registry.
sources:
- name: MyApi
handler:
openapi:
source: https://cdn.graphql-hive.com/asce7c12-753d-hive-bee-d7f2c803e232/sdl?ext=.graphql
schemaHeaders:
X-Hive-CDN-Key: 'aabTxbEyC78NvSPQNO+qLrrRnBvODJJ8k4sL/2EtIwc='
Examples
We have a lot of examples for OpenAPI Handler;
Config API Reference
source
(type:String
, required) - A pointer to your API source (Support both JSON and YAML) - could be a local file, remote file or url endpointfallbackFormat
(type:String (json | yaml | js | ts)
) - Format of the files referenced from the source file, for cases content type isn’t detected automaticallyendpoint
(type:String
) - Specifies the URL on which all paths will be based on. Overrides the server object in the OAS.schemaHeaders
(type:JSON
) - If you are using a remote URL endpoint to fetch your schema, you can set headers for the HTTP request to fetch your schema.operationHeaders
(type:JSON
) - JSON object representing the Headers to add to the runtime of the API callsignoreErrorResponses
(type:Boolean
) - Responses are converted to a Union type grouping all possible responses. Applying this will ignore all responses with status code other than 2xx, resulting in simpler response types, usualy regular object type instead of union. Default: falseselectQueryOrMutationField
(type:Array of Object
) - Allows to explicitly override the default operation (Query or Mutation) for any OAS operation:type
(type:String (query | mutation | Query | Mutation)
, required)fieldName
(type:String
, required)
queryParams
(type:JSON
) - JSON object representing the query search parameters to add to the API callstimeout
(type:Int
) - Timeout for the HTTP request in milliseconds