0.0.19 • Published 7 years ago

senegraph v0.0.19

Weekly downloads
3
License
ISC
Repository
github
Last release
7 years ago

Senegraph

HapiJS and Express plugin connecting SenecaJS and GraphQL:

Do you like Microservices? Do you like GraphQL?

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.

Installation:

npm install --save senegraph

Usage:

HAPI JS :

Here is a simple setup for HapiJS:

import * as hapi from 'hapi';
import { senegraphHapi, hapiql } from 'senegraph';

// setup Hapi server
const server = new hapi.Server();
server.connection({ port: 3000 });

// register the plugins
server.register([{
    register: senegraphHapi,
    options: senegraphOptions,
}, {
    register: hapiql,
    options: {
        path: '/graphiql' // Optional default '/graphiql'
        hapiqlOptions: {
            endpointURL: '/graphql', // required - pointing to the graphQL route
        },
    },
}], (err) => {
    if(err) {
        throw err;
    }
    server.start((error) => {
        if (error) {
          throw error;
        }
        server.log('info', `Server running at: ${server.info.uri}`);
    });
});

Now the senegraphOptions variable can look like this:

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:

  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:

optiontypedescriptionrequired
schemaString!true
resolversObject! or ArrayContaining the resolvers of your graphql schema.true
pathStringThe url for the endpoint route.false Default: '/graphql'
methodsStringArrayThe methods supported for graphql endpointfalse Default: 'GET', 'POST'
setupSenecaFunction (seneca) => {}Is being called at the beginning. This option is optional.false
perRequestPromise OR Function OR Function<Promise>Is being called on every request. Can be Promise or function returning object or function returning Promise. This option is optionalfalse
senecaOptionsObjectThe seneca instantiating options e.g. { log: 'silent' }false Default: {}

HapiQL takes this options:

optiontypedescriptionrequired
pathStringThe path on which the server should serve for graphiqlfalse Default: '/graphiql'
hapiqlOptionsObjectThe options for the hapiql contains endpoint and many more described belowtrue At least endpoint should be provided

hapiqlOptions take these values:

optiontypedescriptionrequired
endpointURLStringthe graphql endpoint by default on address '/graphql'true
subscriptionsEndpointStringEndpoint for subscriptionsfalse
queryStringThe default queryfalse
variablesObjectThe default variablesfalse
operationNameStringThe default operation namefalse
resultObjectThe default resultsfalse

Check out this video: https://youtu.be/VWPVrJU2upw

EXPRESS :
import * as Express from 'express'
import { senegraphExpress, expressiql }

const app = Express();

app.use('/graphql', senegraphExpress(senegraphOptions));
app.use('/graphiql', expressiql({ endpointURL: '/graphql' }));

app.listen(3000)

Now the senegraphOptions could look the same as in Hapi example...

API

SenegraphExpress Options:

optiontypedescriptionrequired
schemaString!true
resolversObject! or ArrayContaining the resolvers of your graphql schema.true
setupSenecaFunction (seneca) => {}Is being called at the beginning. This option is optional.false
perRequestPromise OR Function OR Function<Promise>Is being called on every request. Can be Promise or function returning object or function returning Promise. This option is optionalfalse
senecaOptionsObjectThe seneca instantiating options e.g. { log: 'silent' }false Default: {}

The expressiql options should be in this manner:

optiontypedescriptionrequired
endpointURLStringthe graphql endpoint by default on address '/graphql'true
subscriptionsEndpointStringEndpoint for subscriptionsfalse
queryStringThe default queryfalse
variablesObjectThe default variablesfalse
operationNameStringThe default operation namefalse
resultObjectThe default resultsfalse

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.

import * as Connect from 'connect'
import * as http from 'http'
import { senegraphConnect, connectiql }

const app = Express();

app.use('/graphql', senegraphConnect(senegraphOptions));
app.use('/graphiql', connectiql({ endpointURL: '/graphql' }));

http.createServer(app).listen(3000);

API

The API is the same as in Senegraph Express implementation.

On both server frameworks you can run seneca.actWithPromise which is the act returning a promise.

0.0.19

7 years ago

0.0.18

8 years ago

0.0.17

8 years ago

0.0.16

8 years ago

0.0.15

8 years ago

0.0.14

8 years ago

0.0.13

8 years ago

0.0.12

8 years ago

0.0.11

8 years ago

0.0.10

8 years ago

0.0.9

8 years ago

0.0.8

8 years ago

0.0.7

8 years ago

0.0.6

8 years ago

0.0.5

8 years ago

0.0.4

8 years ago

0.0.3

8 years ago

0.0.2

8 years ago

0.0.1

8 years ago