Me too! Let me then propose this simple plugin for HapiJS and Express Middleware to you. It's fairly simple and flexible tool for creating API endpoints.
$3
`` npm install --save senegraph `
$3
##### HAPI JS : Here is a simple setup for HapiJS:
`javascript import * as hapi from 'hapi'; import { senegraphHapi, hapiql } from 'senegraph';
// setup Hapi server const server = new hapi.Server(); server.connection({ port: 3000 });
senegraphOptions variable can look like this:`javascript const senegraphOptions = { // Setting up the seneca microservices setupSeneca: (seneca) => { // we can return a promise if we need it // to wait for some async operation seneca.add({ role: 'greeter', cmd: 'sayHello' }, (message, done) => { if(message.user) { done(null, { message: 'Hello ' + message.user }); } else { done(new Error('You forgot to tell me who you are')); } }); }, // Setting up the schema (for this example it's pretty simple // but you can for example split it into multiple modules schema: type Query { hello(name: String!): String } , resolvers: { Query: { // third argument is context, which contains // the seneca that we can use for our purpose hello: (root, { name }, { seneca }) => { // we need to use promise // but we could use bluebird's Promisify // on seneca, check the links below return new Promise((resolve, reject) => { seneca.act({ role: 'greeter', cmd: 'sayHello', user: name, }, (err, greetings) => { if(err) { reject(err); } else { resolve(greetings.message); } }); }); } } } } `
To split the schema and/or resolvers into multiple modules take a look at this: http://dev.apollodata.com/tools/graphql-tools/generate-schema.html#modularizing
To modularize SenecaJS into multiple files take a look at this: http://jakepruitt.com/2015/02/09/beginners-guide-to-seneca-js.html
To promisify seneca take a look at this: http://senecajs.org/docs/tutorials/seneca-with-promises.html
-----------------
What if you need to make action for every request called upon your
graphql endpoint? What if you need to provide some additional context and/or root value for your resolvers?
Here's how you do that:
`javascript const senegraphOptions = { schema: mySchema, resolvers: { Query: { hello: ({ myRootData }, args, { seneca, myContextData }) => { // use myRootData = 'random data2' and myContextData = 'random data1' return 'world'; } } }, // This function is called before every request // on your graphql endpoint: perRequest: (seneca) => { // It can either return a value or a Promise return new Promise((resolve) => { setTimeout(() => { resolve({ // returns context and rootValue used in the next graphql call context: { myContextData: 'random data1' }, rootValue: { myRootData: 'random data2' }, }); }, 200); }); } } `
cool isn't it? You can do for example authentication on every single request.
API
SenegraphHapi options:
| option | type | description | required | |:-------------:|:----------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------:| | schema | String! | | true | | resolvers | Object! or Array | Containing the resolvers of your graphql schema. | true | | path | String | The url for the endpoint route. | false Default: '/graphql' | | methods | String | Array | The methods supported for graphql endpoint | false Default: ['GET', 'POST'] | | setupSeneca | Function (seneca) => {} | Is being called at the beginning. This option is optional. | false | | perRequest | Promise
HapiQL takes this options:
| option | type | description | required | |:-------------:|:------:|:--------------------------------------------------------------------------:|:-----------------------------------------:| | path | String | The path on which the server should serve for graphiql | false Default: '/graphiql' | | hapiqlOptions | Object | The options for the hapiql contains endpoint and many more described below | true At least endpoint should be provided |
hapiqlOptions take these values:
| option | type | description | required | |:---------------------:|:------:|:-----------------------------------------------------:|:--------:| | endpointURL | String | the graphql endpoint by default on address '/graphql' | true | | subscriptionsEndpoint | String | Endpoint for subscriptions | false | | query | String | The default query | false | | variables | Object | The default variables | false | | operationName | String | The default operation name | false | | result | Object | The default results | false |
Check out this video: https://youtu.be/VWPVrJU2upw
##### EXPRESS :
`js import * as Express from 'express' import { senegraphExpress, expressiql }
Now the senegraphOptions could look the same as in Hapi example...
API
SenegraphExpress Options:
| option | type | description | required | |:-------------:|:----------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------:|:-----------------:| | schema | String! | | true | | resolvers | Object! or Array | Containing the resolvers of your graphql schema. | true | | setupSeneca | Function (seneca) => {} | Is being called at the beginning. This option is optional. | false | | perRequest | Promise OR Function OR Function> | Is being called on every request. Can be Promise or function returning object or function returning Promise. This option is optional | false | | senecaOptions | Object | The seneca instantiating options e.g. { log: 'silent' } | false Default: {} |
The expressiql options should be in this manner:
| option | type | description | required | |:---------------------:|:------:|:-----------------------------------------------------:|:--------:| | endpointURL | String | the graphql endpoint by default on address '/graphql' | true | | subscriptionsEndpoint | String | Endpoint for subscriptions | false | | query | String | The default query | false | | variables | Object | The default variables | false | | operationName | String | The default operation name | false | | result | Object | The default results | false |
Check out the video on how to use
Senegraph with Express: https://youtu.be/-XHN1T6r_R4
##### CONNECT :
With connect framework it's very similar to Express.
We simply instantiate our server and use the senegraph middleware.
`js import * as Connect from 'connect' import * as http from 'http' import { senegraphConnect, connectiql }