Skip to content

Commit

Permalink
feature: add middlewares for express, koa, hapi (#28)
Browse files Browse the repository at this point in the history
* chore: add middlewares for express, koa, hapi

* chore: add middlewares for express, koa, hapi

* chore: add middlewares for express, koa, hapi

* chore: minor gramma changes after code review

* chore: changes after code review
  • Loading branch information
steplov authored and IvanGoncharov committed Jul 15, 2017
1 parent ba35ed1 commit 9758c6d
Show file tree
Hide file tree
Showing 14 changed files with 354 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ stats.json
npm-debug.log

lib
/middleware/
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ demo-dist
stats.json
npm-debug.log

build
build
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,84 @@ Build for the web with [webpack](https://webpack.js.org/) ([example](./example/w

**Important:** make sure to copy `voyager.worker.js` from `node_modules/graphql-voyager/dist` to the same folder as your main bundle.

## Middleware
Graphql Voyager has middleware for the next frameworks:

### Express

#### Properties
Express middleware supports the following properties:

+ `options`
+ `endpointUrl` [`string`] - the GraphQL endpoint url.

#### Usage
```js
import express from 'express';
import { express as middleware } from 'graphql-voyager/middleware';

const app = express();

app.use('/voyager', middleware({ endpointUrl: '/graphql' }));

app.listen(3000);
```

### Hapi

#### Properties
Hapi middleware supports the following properties:

+ `options`
+ `path` [`string`] - the Voyager middleware url
+ `voyagerOptions`
+ `endpointUrl` [`string`] - the GraphQL endpoint url.

#### Usage
```js
import hapi from 'hapi';
import { hapi as middleware } from 'graphql-voyager/middleware';

const server = new Hapi.Server();

server.connection({
port: 3001
});

server.register({
register: middleware,
options: {
path: '/voyager',
endpointUrl: '/graphql'
}
},() => server.start());
```

### Koa

#### Properties
Koa middleware supports the following properties:

+ `options`
+ `endpointUrl` [`string`] - the GraphQL endpoint url.

#### Usage
```js
import Koa from 'koa';
import KoaRouter from 'koa-router';
import { koa as middleware } from 'graphql-voyager/middleware';

const app = new Koa();
const router = new KoaRouter();

router.all('/voyager', voyagerMiddleware({
endpointUrl: '/graphql'
}));

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3001);
```

## Credits
This tool is inspired by [graphql-visualizer](https://github.com/NathanRSmith/graphql-visualizer) project.
16 changes: 16 additions & 0 deletions example/middleware/express.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { express: voyagerMiddleware } = require('graphql-voyager/middleware');
const schema = require('../schema');

const app = express();
const PORT = 3001;

app.use('/graphql', graphqlHTTP(() => ({ schema })));
app.use('/voyager', voyagerMiddleware({ endpointUrl: '/graphql' }));

app.listen(PORT, function() {
const port = this.address().port;

console.log(`Started on http://localhost:${port}/`);
});
39 changes: 39 additions & 0 deletions example/middleware/hapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const Hapi = require('hapi');
const { graphqlHapi } = require('graphql-server-hapi');
const { hapi: voyagerMiddleware } = require('graphql-voyager/middleware');
const schema = require('../schema');

const server = new Hapi.Server();

server.connection({
port: 3001
});

server.register([
{
register: graphqlHapi,
options: {
path: '/graphql',
graphqlOptions: {
schema,
},
route: {
cors: true
}
}
},
{
register: voyagerMiddleware,
options: {
path: '/voyager',
route: {
cors: true
},
endpointUrl: '/graphql'
},
}
],() => {
server.start(() => {
console.log(`Started on ${server.info.uri}`);
})
});
22 changes: 22 additions & 0 deletions example/middleware/koa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const Koa = require('koa');
const KoaRouter = require('koa-router');
const graphqlHTTP = require('koa-graphql');
const { koa: voyagerMiddleware } = require('graphql-voyager/middleware');
const schema = require('../schema');

const app = new Koa();
const router = new KoaRouter();
const PORT = 3001;

router.all('/graphql', graphqlHTTP({ schema }));
router.all('/voyager', voyagerMiddleware({
endpointUrl: '/graphql'
}));

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(PORT, function() {
const port = this.address().port;

console.log(`Started on http://localhost:${port}/`);
});
7 changes: 6 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
"dependencies": {
"express": "^4.13.3",
"express-graphql": "^0.6.2",
"graphql": "^0.9.0",
"graphql-server-hapi": "^1.0.0",
"graphql-voyager": "../",
"graphql": "^0.9.0"
"hapi": "^16.4.3",
"koa": "^2.3.0",
"koa-graphql": "^0.7.1",
"koa-router": "^7.2.1"
},
"optionalDependencies": {
"react": "^15.4.2",
Expand Down
5 changes: 5 additions & 0 deletions manual-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ declare module "*.css" {
export default content;
}

declare module "*.json" {
const json: any;
export default json;
}

declare var DEBUG_INITIAL_PRESET: string;
declare var DEBUG: boolean;

Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --config build/webpack.demo.js",
"clean:release": "rimraf dist",
"clean:release": "rimraf dist middleware",
"clean:demo": "rimraf demo-dist",
"build:release": "npm run clean:release && NODE_ENV=production webpack --config build/webpack.js && rm dist/voyager.worker.js.map",
"build:release": "npm run clean:release && NODE_ENV=production webpack --config build/webpack.js && rimraf dist/voyager.worker.js.map && tsc src/middleware/index.ts --outDir middleware --lib ES6,DOM",
"build:demo": "npm run clean:demo && NODE_ENV=production webpack -p --config build/webpack.demo.js",
"deploy": "deploy-to-gh-pages --local --update demo-dist",
"stats": "NODE_ENV=production webpack --json -p --config build/webpack.js > stats.json",
Expand All @@ -30,11 +30,14 @@
"css-loader": "^0.28.4",
"deploy-to-gh-pages": "^1.3.6",
"ejs-compiled-loader": "2.2.0",
"express": "^4.15.3",
"extract-text-webpack-plugin": "^2.1.2",
"graphql": "^0.10.3",
"hapi": "^16.4.3",
"hint.css": "^2.5.0",
"html-webpack-plugin": "^2.29.0",
"json-loader": "^0.5.4",
"koa": "^2.3.0",
"postcss-cssnext": "^3.0.0",
"postcss-import": "^10.0.0",
"postcss-loader": "^2.0.6",
Expand Down
28 changes: 28 additions & 0 deletions src/middleware/express.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Request, Response } from 'express';
import renderVoyagerPage, { MiddlewareOptions } from './render-voyager-page';

const { version } = require('../package.json');

interface ExpressVoyagerMiddleware {
(_req: Request, res: Response, next: () => void): void;
}

interface Register {
(options): ExpressVoyagerMiddleware
}

const voyagerExpress: Register = function voyagerExpress(options) {
const middlewareOptions: MiddlewareOptions = {
...options,
version
};

return (_req, res, next) => {
res.setHeader('Content-Type', 'text/html');
res.write(renderVoyagerPage(middlewareOptions));
res.end();
next();
}
};

export default voyagerExpress;
45 changes: 45 additions & 0 deletions src/middleware/hapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Server } from 'hapi';
import renderVoyagerPage, { MiddlewareOptions } from './render-voyager-page';

const pkg = require('../package.json');

interface Register {
(server: Server, options: any, next: any): void;
attributes?: any;
}

const hapi: Register = function(server, options, next) {
if (arguments.length !== 3) {
throw new Error(`Voyager middleware expects exactly 3 arguments, got ${arguments.length}`);
}

const {
path,
route: config = {},
...voyagerOptions
} = options;

const middlewareOptions: MiddlewareOptions = {
...voyagerOptions,
version: pkg.version
};

server.route({
method: 'GET',
path,
config,
handler: (_request, reply) => {
reply(renderVoyagerPage(middlewareOptions))
.header('Content-Type', 'text/html')
},
});

return next();
};

hapi.attributes = {
pkg,
multiple: false
};

export default hapi;
11 changes: 11 additions & 0 deletions src/middleware/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { default as express } from './express';
import { default as hapi } from './hapi';
import { default as koa } from './koa';
import { default as renderVoyagerPage } from './render-voyager-page';

export {
express,
hapi,
koa,
renderVoyagerPage
}
31 changes: 31 additions & 0 deletions src/middleware/koa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Context } from 'koa';
import renderVoyagerPage, { MiddlewareOptions } from './render-voyager-page';

const { version } = require('../package.json');

interface KoaVoyagerMiddleware {
(ctx: Context, next: () => void): void;
}

interface Register {
(options): KoaVoyagerMiddleware
}

const koa: Register = function (options) {
const middlewareOptions: MiddlewareOptions = {
...options,
version
};

return async function voyager(ctx, next) {
try {
ctx.body = renderVoyagerPage(middlewareOptions);
await next();
} catch (err) {
ctx.body = {message: err.message};
ctx.status = err.status || 500
}
}
};

export default koa;

0 comments on commit 9758c6d

Please sign in to comment.