Merge remote-tracking branch 'apollostack/master'

This commit is contained in:
Nicolás López 2016-09-10 12:18:45 -03:00
commit e58554806f
12 changed files with 67 additions and 39 deletions

View file

@ -1,12 +1,16 @@
# Changelog
### v0.3.0
* Refactor HAPI integration to improve the API and make the plugins more idiomatic. ([@nnance](https://github.com/nnance)) in
* Refactor Hapi integration to improve the API and make the plugins more idiomatic. ([@nnance](https://github.com/nnance)) in
[PR #127](https://github.com/apollostack/apollo-server/pull/127)
* Fixed query batching with HAPI integration. Issue #123 ([@nnance](https://github.com/nnance)) in
* Fixed query batching with Hapi integration. Issue #123 ([@nnance](https://github.com/nnance)) in
[PR #127](https://github.com/apollostack/apollo-server/pull/127)
* Add support for route options in HAPI integration. Issue #97. ([@nnance](https://github.com/nnance)) in
* Add support for route options in Hapi integration. Issue #97. ([@nnance](https://github.com/nnance)) in
[PR #127](https://github.com/apollostack/apollo-server/pull/127)
* Camelcase Hapi. Issue #129. ([@nnance](https://github.com/nnance)) in
[PR #132](https://github.com/apollostack/apollo-server/pull/132)
* Fix error handling when parsing variables parameter. Issue #130. ([@nnance](https://github.com/nnance)) in
[PR #131](https://github.com/apollostack/apollo-server/pull/131)
### v0.2.6
* Expose the OperationStore as part of the public API. ([@nnance](https://github.com/nnance))
@ -21,13 +25,13 @@
### v0.2.1
* Complete refactor of Apollo Server using TypeScript. PR [#41](https://github.com/apollostack/apollo-server/pull/41)
* Added HAPI integration ([@nnance](https://github.com/nnance) in [#46](https://github.com/apollostack/apollo-server/pull/46))
* Added Hapi integration ([@nnance](https://github.com/nnance) in [#46](https://github.com/apollostack/apollo-server/pull/46))
* Added Koa integration ([@HriBB](https://github.com/HriBB) in [#59](https://github.com/apollostack/apollo-server/pull/59))
* Changed express integration to support connect as well ([@helfer](https://github.com/helfer) in [#58](https://github.com/apollostack/apollo-server/pull/58))
* Dropped express-graphql dependency
* Dropped support for GET requests, only POST requests are allowed now
* Split GraphiQL into a separate middleware
* Factored out core to support HAPI, Koa and connect implementations
* Factored out core to support Hapi, Koa and connect implementations
* Added support for query batching
* Added support for query whitelisting / stored queries
* Removed body parsing from express integration. Body must be parsed outside of apollo now

View file

@ -16,7 +16,7 @@ At the core of Apollo Server is a function called `runQuery`, which handles pars
The main goals of Apollo Server are (in order of priority):
1. Simplicity: Apollo Servers core API is very straight forward. Its one function that does one thing really well (parsing, validating and executing GraphQL queries), and doesnt do anything else.
2. Flexibility: The core of Apollo Server should be transport-agnostic (e.g. it doesnt deal with HTTP or Websockets directly. This is will be handled in the wrappers for Express, HAPI, etc.)
2. Flexibility: The core of Apollo Server should be transport-agnostic (e.g. it doesnt deal with HTTP or Websockets directly. This is will be handled in the wrappers for Express, Hapi, etc.)
3. Performance: Apollo server should be be tunable to make it fast in production. One example of this is that it should be able to take pre-stored queries to skip parsing and validation. It should also allow easy integration of profiling tools like Apollo Tracer that help with debugging and optimizing server performance.
### Integrations
@ -24,7 +24,7 @@ The main goals of Apollo Server are (in order of priority):
Apollo Server should come with a set of integrations for different Node.js server frameworks:
- Express
- HAPI
- Hapi
- Connect
- Koa
- ...

View file

@ -1,11 +1,11 @@
# GraphQL Server for Express, Connect, HAPI and Koa
# GraphQL Server for Express, Connect, Hapi and Koa
[![npm version](https://badge.fury.io/js/apollo-server.svg)](https://badge.fury.io/js/apollo-server)
[![Build Status](https://travis-ci.org/apollostack/apollo-server.svg?branch=master)](https://travis-ci.org/apollostack/apollo-server)
[![Coverage Status](https://coveralls.io/repos/github/apollostack/apollo-server/badge.svg?branch=master)](https://coveralls.io/github/apollostack/apollo-server?branch=master)
[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](http://www.apollostack.com/#slack)
Apollo Server is a community-maintained open-source GraphQL server. It works with all Node.js HTTP server frameworks: Express, Connect, HAPI and Koa.
Apollo Server is a community-maintained open-source GraphQL server. It works with all Node.js HTTP server frameworks: Express, Connect, Hapi and Koa.
## Principles
@ -64,13 +64,13 @@ app.use('/graphql', bodyParser.json(), apolloConnect({ schema: myGraphQLSchema }
app.listen(PORT);
```
### HAPI
### Hapi
Now with the HAPI plugins `ApolloHAPI` and `GraphiQLHAPI` you can pass a route object that includes options to be applied to the route. The example below enables CORS on the `/graphql` route.
Now with the Hapi plugins `ApolloHapi` and `GraphiQLHapi` you can pass a route object that includes options to be applied to the route. The example below enables CORS on the `/graphql` route.
```js
import hapi from 'hapi';
import { ApolloHAPI } from 'apollo-server';
import { ApolloHapi } from 'apollo-server';
const server = new hapi.Server();
@ -83,7 +83,7 @@ server.connection({
});
server.register({
register: ApolloHAPI,
register: ApolloHapi,
options: {
path: '/graphql',
apolloOptions: {
@ -155,7 +155,7 @@ apolloOptions = {
Apollo Server and express-graphql are more or less the same thing (GraphQL middleware for Node.js), but there are a few key differences:
* express-graphql works with Express and Connect, Apollo Server supports Express, Connect, HAPI and Koa.
* express-graphql works with Express and Connect, Apollo Server supports Express, Connect, Hapi and Koa.
* express-graphql's main goal is to be a minimal reference implementation, whereas Apollo Server's goal is to be a complete production-ready GraphQL server.
* Compared to express-graphql, Apollo Server has a simpler interface and supports exactly one way of passing queries.
* Apollo Server separates serving GraphiQL (GraphQL UI) from responding to GraphQL requests.

View file

@ -12,7 +12,7 @@ This document contains a rough outline of a roadmap and a few designs for future
* Express integration
* Query batching (Express)
* Query whitelisting / stored queries
* HAPI integration
* Hapi integration
* Koa integration
* Connect integration
* Complete rewrite of Apollo Server documentation

View file

@ -1,7 +1,7 @@
{
"name": "apollo-server",
"version": "0.2.8",
"description": "Production-ready Node.js GraphQL server for Express, HAPI, Koa",
"description": "Production-ready Node.js GraphQL server for Express, Hapi, Koa",
"main": "dist/index.js",
"directories": {
"test": "test"
@ -25,7 +25,7 @@
"keywords": [
"GraphQL",
"Apollo",
"HAPI",
"Hapi",
"Koa",
"Express",
"Javascript"

View file

@ -2,7 +2,7 @@ export { runQuery } from './core/runQuery'
export { renderGraphiQL} from './modules/renderGraphiQL'
export { OperationStore } from './modules/operationStore'
export { apolloExpress, graphiqlExpress } from './integrations/expressApollo'
export { ApolloHAPI, GraphiQLHAPI } from './integrations/hapiApollo'
export { ApolloHapi, GraphiQLHapi } from './integrations/hapiApollo'
export { apolloKoa, graphiqlKoa } from './integrations/koaApollo'
export { apolloConnect, graphiqlConnect } from './integrations/connectApollo'
export { default as ApolloOptions} from './integrations/apolloOptions'

View file

@ -77,8 +77,14 @@ export function apolloExpress(options: ApolloOptions | ExpressApolloOptionsFunct
let variables = requestParams.variables;
if (typeof variables === 'string') {
// TODO: catch errors
variables = JSON.parse(variables);
try {
variables = JSON.parse(variables);
} catch (error) {
res.statusCode = 400;
res.write('Variables are invalid JSON.');
res.end();
return;
}
}
let params = {

View file

@ -1,9 +1,9 @@
import * as hapi from 'hapi';
import { ApolloHAPI, GraphiQLHAPI, HAPIPluginOptions } from './hapiApollo';
import { ApolloHapi, GraphiQLHapi, HapiPluginOptions } from './hapiApollo';
import testSuite, { Schema } from './integrations.test';
function createApp(createOptions: HAPIPluginOptions) {
function createApp(createOptions: HapiPluginOptions) {
const server = new hapi.Server();
server.connection({
@ -12,7 +12,7 @@ function createApp(createOptions: HAPIPluginOptions) {
});
server.register({
register: ApolloHAPI,
register: ApolloHapi,
options: {
apolloOptions: createOptions ? createOptions.apolloOptions : { schema: Schema },
path: '/graphql',
@ -20,7 +20,7 @@ function createApp(createOptions: HAPIPluginOptions) {
});
server.register({
register: GraphiQLHAPI,
register: GraphiQLHapi,
options: {
path: '/graphiql',
graphiqlOptions: {
@ -32,6 +32,6 @@ function createApp(createOptions: HAPIPluginOptions) {
return server.listener;
}
describe('integration:HAPI', () => {
describe('integration:Hapi', () => {
testSuite(createApp);
});

View file

@ -11,17 +11,17 @@ export interface IRegister {
attributes?: any;
}
export interface HAPIOptionsFunction {
export interface HapiOptionsFunction {
(req?: Request): ApolloOptions | Promise<ApolloOptions>;
}
export interface HAPIPluginOptions {
export interface HapiPluginOptions {
path: string;
route?: any;
apolloOptions: ApolloOptions | HAPIOptionsFunction;
apolloOptions: ApolloOptions | HapiOptionsFunction;
}
const ApolloHAPI: IRegister = function(server: Server, options: HAPIPluginOptions, next) {
const ApolloHapi: IRegister = function(server: Server, options: HapiPluginOptions, next) {
server.method('verifyPayload', verifyPayload);
server.method('getGraphQLParams', getGraphQLParams);
server.method('getApolloOptions', getApolloOptions);
@ -68,7 +68,7 @@ const ApolloHAPI: IRegister = function(server: Server, options: HAPIPluginOption
return next();
};
ApolloHAPI.attributes = {
ApolloHapi.attributes = {
name: 'graphql',
version: '0.0.1',
};
@ -113,7 +113,7 @@ async function getApolloOptions(request: Request, reply: IReply): Promise<{}> {
let optionsObject: ApolloOptions;
if (isOptionsFunction(options)) {
try {
const opsFunc: HAPIOptionsFunction = <HAPIOptionsFunction>options;
const opsFunc: HapiOptionsFunction = <HapiOptionsFunction>options;
optionsObject = await opsFunc(request);
} catch (e) {
return reply(createErr(500, `Invalid options provided to ApolloServer: ${e.message}`));
@ -155,7 +155,7 @@ async function processQuery(graphqlParams, optionsObject: ApolloOptions, reply)
return reply(responses);
}
function isOptionsFunction(arg: ApolloOptions | HAPIOptionsFunction): arg is HAPIOptionsFunction {
function isOptionsFunction(arg: ApolloOptions | HapiOptionsFunction): arg is HapiOptionsFunction {
return typeof arg === 'function';
}
@ -171,7 +171,7 @@ export interface GraphiQLPluginOptions {
graphiqlOptions: GraphiQL.GraphiQLData;
}
const GraphiQLHAPI: IRegister = function(server: Server, options: GraphiQLPluginOptions, next) {
const GraphiQLHapi: IRegister = function(server: Server, options: GraphiQLPluginOptions, next) {
server.method('getGraphiQLParams', getGraphiQLParams);
server.method('renderGraphiQL', renderGraphiQL);
@ -199,7 +199,7 @@ const GraphiQLHAPI: IRegister = function(server: Server, options: GraphiQLPlugi
next();
};
GraphiQLHAPI.attributes = {
GraphiQLHapi.attributes = {
name: 'graphiql',
version: '0.0.1',
};
@ -223,4 +223,4 @@ function renderGraphiQL(route, graphiqlParams: any, reply) {
reply(graphiQLString);
}
export { ApolloHAPI, GraphiQLHAPI };
export { ApolloHapi, GraphiQLHapi };

View file

@ -161,7 +161,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
.send();
return req.then((res) => {
expect(res.status).to.be.oneOf([404, 405]);
// HAPI doesn't return allow header, so we can't test this.
// Hapi doesn't return allow header, so we can't test this.
// return expect(res.headers['allow']).to.equal('POST');
});
});
@ -228,6 +228,20 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
});
});
it('can handle a request with variables as an invalid string', () => {
app = createApp();
const req = request(app)
.post('/graphql')
.send({
query: 'query test($echo: String!){ testArgument(echo: $echo) }',
variables: '{ echo: "world" }',
});
return req.then((res) => {
expect(res.status).to.equal(400);
return expect(res.error.text).to.contain('Variables are invalid JSON.');
});
});
it('can handle a request with operationName', () => {
app = createApp();
const expected = {

View file

@ -56,8 +56,12 @@ export function apolloKoa(options: ApolloOptions | KoaApolloOptionsFunction): Ko
let variables = requestParams.variables;
if (typeof variables === 'string') {
// TODO: catch errors
variables = JSON.parse(variables);
try {
variables = JSON.parse(variables);
} catch (error) {
ctx.status = 400;
return ctx.body = 'Variables are invalid JSON.';
}
}
let params = {

View file

@ -3,7 +3,7 @@
// TODO: maybe we should get rid of these tests entirely, and move them to expressApollo.test.ts
// TODO: wherever possible the tests should be rewritten to make them easily work with HAPI, express, Koa etc.
// TODO: wherever possible the tests should be rewritten to make them easily work with Hapi, express, Koa etc.
/*
* Below are the HTTP tests from express-graphql. We're using them here to make