Aeros
Simplified GraphQL Schema generation, built on graphql-tools
Overview
Aeros constructs a fully valid GraphQL schema, along with type definitions and resolvers, based off a simple javascript object. It allows you to write your GraphQL schemas in a testable, lintable manner, as well as co-locate your resolvers with that same schema definition.
Built on top of graphql-tools
, and using portions of their syntax, Aeros constructs the GraphQL DSL string for you, from the provided configuration objects, and converts it into your executable schema.
tl;dr GraphQL schemas with no transforms, no build steps, just simple javascript.
Now with Subscription support!
Quickstart
All you need are two files: schema.js
(the Aeros implementation) and index.js
(in this example, a graphql-server-micro installation)
// install aeros
npm i -s aeros
// install supporting libraries for quickstart
npm i -s graphql-server-micro micro microrouter
const Aeros = require('aeros')
const query = {
user: {
type: 'User',
params: {
id: 'String'
},
resolver: (_, { id }, ctx) => ({ id, email: 'janedoe@example.com', name: 'Jane Doe' })
}
}
const types = {
User: {
id: 'String!',
email: 'String',
name: 'String',
address: {
type: 'String',
resolver: (user, _, ctx) => {
return '350 Awesome St. Exampleville, CA'
}
}
}
}
module.exports = Aeros({ query, types }).schema
const { microGraphiql, microGraphql } = require("graphql-server-micro")
const micro = require("micro")
const { send } = micro
const { get, post, router } = require("microrouter")
const schema = require("./schema")
const graphqlHandler = microGraphql({ schema });
const graphiqlHandler = microGraphiql({ endpointURL: "/graphql" });
const server = micro(
router(
get("/graphql", graphqlHandler),
post("/graphql", graphqlHandler),
get("/graphiql", graphiqlHandler),
(req, res) => send(res, 404, "not found"),
),
);
server.listen(3000);
You should see a working graphiql interface on http://localhost:3000/graphiql.
API Documentation
Object Structure
All of the objects passed into Aeros follows the same structure, an object with named properties. Those properties can be a a string (which is just a simple type definition), or an object with type
and resolver
properties within it.
type
is just a string, and follows graphql-tools
DSL syntax for type definitions (e.g. "String"
, "Boolean!"
, "UserDefinedType"
, etc.)
resolver
can be a function, a promise, or a subscription object, containing at the very least subscribe
as a property, with the optional resolve
property if you want to manipulate the response from the subscription. This is the same as you would pass into graphql-tools
in the resolvers object.
Additionally, you can specify params
within the object, which will allow you to specify the parameter names and types of the resolver.
Here are a few examples:
Simple Resolver
// schema.js
const query = {
getFoobar: {
type: 'String!',
resolver: (_, __, ctx) => 'foobar'
}
}
const { schema } = new Aeros({ query })
is the same as two separate configurations for graphql-tools
, which you would need to import separately and build to inject into the library properly:
// getFoobar.graphql
type Query {
getFoobar: String
}
// getFoobar.js
export default (_, __, ctx) => 'foobar';
// schema.js
import getFoobar from './getFoobar';
// import the graphql file using whatever build system you use
const resolvers = {
Query: {
getFoobar
}
}
const typeDefs = [getFoobarSchema]
const schemaConfig = { typeDefs, resolvers }
const schema = makeExecutableSchema(schemaConfig)
Alternatively, you could save the graphql DSL as a js template string and skip the build step, but you still wouldn't be able to test/lint that it was written correctly / matches the resolver definition, at least not with your standard js testing setup.
Resolver with Parameters
const query = {
getUser: {
type: 'String',
params: {
id: 'String!'
}
resolver: (_, { id }, ctx) => 'user'
}
}
const { schema } = new Aeros({ query })
Resolver with Subscription
const subscription = {
getUser: {
type: 'String',
params: {
id: 'String!'
}
resolver: {
subscribe: (_, { id }, ctx) => pubsub.asyncIterator('commentAdded')
}
}
}
const { schema } = new Aeros({ subscription })
Resolver with custom type
// schema.js
const query = {
getUser: {
type: 'User',
resolver: (_, __, ctx) => ({ name: 'Jane', email: 'jane@example.com' })
}
}
const types = {
User: {
name: 'String',
email: 'String'
}
}
const { schema } = new Aeros({ query, types })
Every option demo
// schema.js
const query = {
getUser: {
type: 'User',
params: {
id: 'String!'
},
resolver: (_, { id }, ctx) => ({ name: 'Jane', email: 'jane@example.com' })
}
}
const mutation = {
updateUser: {
type: 'User',
params: {
id: 'String!',
email: 'String'
},
resolver: (_, { id, email }, ctx) => {
// perform side effect here
}
}
}
const subscription = {
userCommented: {
type: 'String',
params: {
id: 'String!'
}
resolver: {
subscribe: (_, { id }, ctx) => pubsub.asyncIterator('commentAdded')
}
}
}
const types = {
User: {
name: 'String',
email: 'String'
}
}
const { schema } = new Aeros({ query, mutation, subscription, types })
Support
If you run into an issue, please [open an issue] on Github, and I'll do my best to address your concern. Please keep in mind that this is a side-project of mine and not sponsored by any company in particular, so release cadence may not be very timely.
Contribution
Want to add a feature or fix a bug? Please do! Make sure you comment in an issue somewhere that you're working on it (so others know and don't duplicate efforts), fork this repo and open a pull request! I'll work with you on the PR for any housekeeping items (making sure it matches code styling, things like that), and if we're all in agreement, merge it in and release it.
New to coding? or GraphQL? Not to worry, I'm happy to help / point you in the right direction. I promise I don't bite :kissing_heart:
License
The MIT License (MIT)
Copyright (c) 2018 Oz Haven (@therebelrobot) npm@therebelrobot.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.