diff --git a/CHANGELOG.md b/CHANGELOG.md index 078d13f7e90..79b31382f7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Added `formatRequest` and `formatResponse` functions to apollo options. * Removed support for shorthand schema definitions, connectors and mocks (use `graphql-tools` instead) * Added Koa integration (@HriBB in #59) +* Changed express integration to support connect as well (@helfer in #58) ### v0.1.5 diff --git a/package.json b/package.json index 890a7eb8565..d940bc40624 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "babel-preset-es2015": "^6.9.0", "body-parser": "^1.15.2", "chai": "^3.5.0", + "connect": "^3.4.1", "istanbul": "1.0.0-alpha.2", "koa-bodyparser": "^3.0.0", "koa-router": "^7.0.1", diff --git a/src/index.ts b/src/index.ts index 1ca411ee3c1..6f7c076e747 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export { apolloExpress, graphiqlExpress } from './integrations/expressApollo'; export { ApolloHAPI, GraphiQLHAPI } from './integrations/hapiApollo'; export { apolloKoa } from './integrations/koaApollo'; +export { apolloConnect, graphiqlConnect } from './integrations/connectApollo'; diff --git a/src/integrations/connectApollo.test.ts b/src/integrations/connectApollo.test.ts new file mode 100644 index 00000000000..a901ed32f74 --- /dev/null +++ b/src/integrations/connectApollo.test.ts @@ -0,0 +1,23 @@ +import * as connect from 'connect'; +import * as bodyParser from 'body-parser'; +import { apolloConnect, graphiqlConnect } from './connectApollo'; + +import testSuite, { Schema, CreateAppOptions } from './integrations.test'; + +function createConnectApp(options: CreateAppOptions = {}) { + const app = connect(); + + options.apolloOptions = options.apolloOptions || { schema: Schema }; + if (!options.excludeParser) { + app.use('/graphql', bodyParser.json()); + } + if (options.graphiqlOptions ) { + app.use('/graphiql', graphiqlConnect( options.graphiqlOptions )); + } + app.use('/graphql', apolloConnect( options.apolloOptions )); + return app; +} + +describe('integration:Connect', () => { + testSuite(createConnectApp); +}); diff --git a/src/integrations/connectApollo.ts b/src/integrations/connectApollo.ts new file mode 100644 index 00000000000..5e2a35cd4ae --- /dev/null +++ b/src/integrations/connectApollo.ts @@ -0,0 +1,6 @@ +import { apolloExpress, graphiqlExpress } from './expressApollo'; + +const apolloConnect = apolloExpress; +const graphiqlConnect = graphiqlExpress; + +export { apolloConnect, graphiqlConnect }; diff --git a/src/integrations/expressApollo.ts b/src/integrations/expressApollo.ts index 38b7135a50c..6cb177b9303 100644 --- a/src/integrations/expressApollo.ts +++ b/src/integrations/expressApollo.ts @@ -1,5 +1,6 @@ import * as express from 'express'; import * as graphql from 'graphql'; +import * as url from 'url'; import { runQuery } from '../core/runQuery'; import ApolloOptions from './apolloOptions'; @@ -34,8 +35,9 @@ export function apolloExpress(options: ApolloOptions | ExpressApolloOptionsFunct try { optionsObject = await options(req); } catch (e) { - res.status(500); - res.send(`Invalid options provided to ApolloServer: ${e.message}`); + res.statusCode = 500; + res.write(`Invalid options provided to ApolloServer: ${e.message}`); + res.end(); } } else { optionsObject = options; @@ -45,14 +47,16 @@ export function apolloExpress(options: ApolloOptions | ExpressApolloOptionsFunct if (req.method !== 'POST') { res.setHeader('Allow', 'POST'); - res.status(405); - res.send('Apollo Server supports only POST requests.'); + res.statusCode = 405; + res.write('Apollo Server supports only POST requests.'); + res.end(); return; } if (!req.body) { - res.status(500); - res.send('POST body missing. Did you forget "app.use(bodyParser.json())"?'); + res.statusCode = 500; + res.write('POST body missing. Did you forget "app.use(bodyParser.json())"?'); + res.end(); return; } @@ -100,15 +104,17 @@ export function apolloExpress(options: ApolloOptions | ExpressApolloOptionsFunct } } - res.set('Content-Type', 'application/json'); + res.setHeader('Content-Type', 'application/json'); if (isBatch) { - res.send(JSON.stringify(responses)); + res.write(JSON.stringify(responses)); + res.end(); } else { const gqlResponse = responses[0]; if (gqlResponse.errors && typeof gqlResponse.data === 'undefined') { - res.status(400); + res.statusCode = 400; } - res.send(JSON.stringify(gqlResponse)); + res.write(JSON.stringify(gqlResponse)); + res.end(); } }; @@ -131,8 +137,7 @@ function isOptionsFunction(arg: ApolloOptions | ExpressApolloOptionsFunction): a export function graphiqlExpress(options: GraphiQL.GraphiQLData) { return (req: express.Request, res: express.Response, next) => { - - const q = req.query || {}; + const q = req.url && url.parse(req.url, true).query || {}; const query = q.query || ''; const variables = q.variables || '{}'; const operationName = q.operationName || ''; @@ -144,7 +149,8 @@ export function graphiqlExpress(options: GraphiQL.GraphiQLData) { variables: JSON.parse(variables) || options.variables, operationName: operationName || options.operationName, }); - res.set('Content-Type', 'text/html'); - res.send(graphiQLString); + res.setHeader('Content-Type', 'text/html'); + res.write(graphiQLString); + res.end(); }; } diff --git a/src/test/tests.ts b/src/test/tests.ts index 3e286e837d1..0752fcfb103 100644 --- a/src/test/tests.ts +++ b/src/test/tests.ts @@ -9,6 +9,7 @@ require('source-map-support').install(); import '../core/runQuery.test'; import '../modules/operationStore.test'; import '../integrations/expressApollo.test'; +import '../integrations/connectApollo.test'; import '../integrations/hapiApollo.test'; import '../integrations/koaApollo.test'; import './testApolloServerHTTP'; diff --git a/typings.json b/typings.json index 2981f9363fa..dcbc724fa94 100644 --- a/typings.json +++ b/typings.json @@ -7,6 +7,7 @@ "globalDependencies": { "body-parser": "registry:dt/body-parser#0.0.0+20160619023215", "cookies": "registry:dt/cookies#0.5.1+20160316171810", + "connect": "registry:dt/connect#3.4.0+20160317120654", "express": "registry:dt/express#4.0.0+20160708185218", "express-serve-static-core": "registry:dt/express-serve-static-core#4.0.0+20160715232503", "hapi": "registry:dt/hapi#13.0.0+20160709092105",