Graphql Connector
This library is designed to easily connect a existing database system to the graphql ecosystem.
It takes the types and models of the source system and maps them to GraphQL.
Usage
The connector needs to know 2 things to work:
- a ModelMapper to convert a Model from the source system into the GraphQL Connector Model-Type
- a TypeMapper to convert a Datatype of the source system into a GraphQLType
To see it in action you can look at the code for this example in the tests.
This code will be kept up to date and be used as a test
@TODO: subscriptions are not in yet
First step, define a graphql-connector model mapper
import {
createModelMapper,
} from 'graphql-connector'
type Models = typeof myModels
type Types = typeof myTypes
const isListType = (type: myTypes.DBType): type is myTypes.DBListType => type instanceof myTypes.DBListType
const getFinalType = (type: myTypes.DBType) => (isListType(type) ? type.subtype : type)
const modelMapper = createModelMapper<myTypes.DBType, Models>((model, addAttribute, addAssociation) => {
Object.keys(model.attributes).forEach(name => {
const attribute = model.attributes[name]
const type = getFinalType(attribute)
const list = isListType(attribute)
if (name !== 'id' && type instanceof myTypes.DBIDType)
return addAssociation({
list,
model: type.source as any,
name,
})
return addAttribute({
list,
name,
type,
})
})
})
Next step is to create a type mapper to convert our my-types into GraphQLType
import { TypeMapper } from 'graphql-connector'
const typeMapper: TypeMapper<Types, Models> = ({ type }) => {
if (type instanceof myTypes.DBIDType) return GraphQLID
if (type instanceof myTypes.DBDateType) return DateType
if (type instanceof myTypes.DBIntType) return GraphQLInt
if (type instanceof myTypes.DBStringType) return GraphQLString
throw new Error('invalid type: ' + typeof type)
}
The last step is to input the typeMapper and the modelMapper into the createBaseSchema function and use the result to generate a BaseSchema
const baseSchemaGenerator = createBaseSchemaGenerator({
modelMapper,
typeMapper,
})
const baseSchema = baseSchemaGenerator(myModels)
Now we have generated all required queryFields, mutationFields and subscriptionFields.
These now need to be converted to a GraphQLSchema, there is a utility function for it, but the step uses graphql code only.
import {
GraphQLObjectType,
GraphQLSchema,
} from 'graphql'
export const createSchema = ({ queryFields, mutationFields }: BaseSchema) =>
new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: queryFields,
}),
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: mutationFields,
}),
})
const schema = createSchema(baseSchema)
This results in an SDL like:
type Comment implements Node {
msg: String
id: ID
createdAt: Date
lastUpdate: Date
commentor: User
Post: Post
}
type Comments implements List {
nodes: [Comment!]!
page: Page!
}
"""
A special custom Scalar type for Dates that converts to a ISO formatted string
"""
scalar Date
interface List {
nodes: [Node!]!
page: Page!
}
type Mutation {
createUser: User
updateUser: User
deleteUsers: Users
createPost: Post
updatePost: Post
deletePosts: Posts
createComment: Comment
updateComment: Comment
deleteComments: Comments
}
interface Node {
id: ID
}
type Page {
limit: Int
offset: Int
}
type Post implements Node {
title: String
text: String
upvotes: Int
id: ID
createdAt: Date
lastUpdate: Date
author: User
Comment: Comments
}
type Posts implements List {
nodes: [Post!]!
page: Page!
}
type Query {
User: User
Users: Users
Post: Post
Posts: Posts
Comment: Comment
Comments: Comments
}
type User implements Node {
name: String
email: String
password: String
id: ID
createdAt: Date
lastUpdate: Date
Post: Posts
Comment: Comments
}
type Users implements List {
nodes: [User!]!
page: Page!
}