⚠️ Work in Progress, please use at your own risk and report bugs.
Generates graphql schema from Swagger/OpenAPI spec file. Provides GraphQL resolver factories for http and faker.
- Support for Swagger 2.x
- Parse interfaces
- Parse unions
- Fetch fields recursively
- Create complex example and write docs
x-links
- Write docs for options
- Write docs for resolver factory options
- Cache same requests in one query
- Support for OpenAPI 3.x
$ yarn add https://github.com/brabeji/swagger-graphql-schema.git#a9882cdf79ebe520d3e85756d9e4e4706881562a
Having this simple swaggerfile:
swagger: '2'
host: example.com
schemes:
- https
basePath: /api
definitions:
Node:
title: Node # assigns name to resulting type.
# Generally all object schemas and schemas containing allOf or anyOf should have a title to avoid errors.
type: object
# Either GraphQLObjectType, GraphQLInputObjectType or GraphQLInterfaceType is be generated from object schema.
# Which exact type is generated depends on where the schema is referenced. Explanation is below.
properties:
id:
type: string
format: uuid # "uuid" and "uniqueId" formats will result into GraphQLID
readOnly: true
required:
- id # makes field non-nullable
Tag:
title: Tag
type: object
properties:
name:
type: string
format: uniqueId
required:
- name
Post:
title: Some descriptive title
x-typeName: Post # when present, x-typeName takes precendence over title in specifying name of type
allOf:
- $ref: '#/definitions/Node' # GraphQLInterfaceType is generated when object schema is encountered under allOf
# Referencing Node schema both inside and outside of allOf will result in duplicate type name error.
# Either choose a schema to be an interface or object type. Do not nest interfaces using allOf or anyOf
# as that doesn't conform to GraphQL interfaces structure - this may be solved by flattening allOf in future.
- type: object
properties:
title:
type: string
authorEmail:
type: string
format: email # email (graphql-scalars), json (graphql-type-json) TODO: date, time, date-time (graphql-iso-date)
status:
type: string
# title: PostStatus
enum: # add enum from GraphQLEnumType. The type will by default be named Post_status unless a different name is specified by title.
- PUBLISHED
- DELETED
tags:
type: array
items:
$ref: '#/definitions/Tag'
paths:
/search:
get:
operationId: search # this operation (GET /search) will turn into a query named "search"
parameters:
- in: query # the query will have non-nullable String argument named "query"
name: q
type: string
required: true
responses:
200:
schema:
type: array # generates GraphQLList
items:
# Generates GraphQLUnionType
title: SearchResultItem # assigns SearchResultItem as a name to the union type
anyOf: # specifies that SearchResultItem is union of different types.
# anyOf is invalid in Swagger 2.0 but will be specified in OpenAPI 3.x, see readme TODOs
- $ref: '#/definitions/Post'
- $ref: '#/definitions/Tag'
/posts:
post:
operationId: createPost # this operation (POST /posts) will turn into a mutation named "createPost"
parameters:
- in: body
name: input
schema:
$ref: '#/definitions/Post'
# Referencing object type in body parameter schema generates GraphQLInputObjectType with "Input" appended to
# original name, "PostInput" in this case. readOnly properties are removed.
# Post_tagsInput
responses:
200:
schema:
$ref: '#/definitions/Post' # Using same schema for parameter and response conforms to some REST recommendations and isn't required.
# Generally, this can be something completely different than Post.
Convert it to graphql schema:
import RefParser from 'json-schema-ref-parser';
import swaggerToSchema, { dereferenceLocalAbsoluteJsonPointers } from 'swagger-graphql-schema';
import createHttpResolver from 'swagger-graphql-schema/lib/createHttpResolver';
// OR import createFakerResolver from 'swagger-graphql-schema/lib/createFakerResolver';
import { printSchema } from 'graphql';
RefParser
// swagger-graphql-schema accepts possibly cyclic js object without json pointers
// so your yaml file should be bundled with json-schema-ref-parser and
// then dereferenced using built-in utility function.
// Dereferencing using json-schema-ref-parser's dereference() is slow
// for large schemas
.bundle(path.resolve(__dirname, './examples/simple/swagger.yml'))
.then(
(bundledSwagger) => {
const schema = swaggerToSchema(
{
schema: dereferenceLocalAbsoluteJsonPointers(bundledSwagger),
createResolver: createHttpResolver,
// createResolver: createFakerResolver, for json-schema-faker data
}
);
console.log(printSchema(schema));
}
);
Outputs:
scalar EmailAddress
type Mutation {
createPost(input: PostInput): Post
}
interface Node {
id: ID!
}
type Post implements Node {
id: ID!
title: String
authorEmail: EmailAddress
status: Post_status
tags: [Tag]
}
enum Post_status {
PUBLISHED
DELETED
}
input Post_tagsInput {
name: ID
}
input PostInput {
title: String
authorEmail: EmailAddress
status: Post_status
tags: [Post_tagsInput]
}
type Query {
search(q: String!): [SearchResultItem]
}
union SearchResultItem = Post | Tag
type Tag {
name: ID!
}
When creating schema, swagger-graphql-schema
calls createResolver
to obtain field resolver.
Parsed information about http request (swagger assumes http), input and output json schemas are passed to createResolver
.
At this time, two resolver factories are included
createHttpResolver
- makes http call based onschemes
,host
,basePath
and operation as defined in swaggerfilecreateFakerResolver
- deterministic result ofjson-schema-faker
MIT