apollo-server-express
Advanced tools
Comparing version 1.3.2 to 1.3.3
@@ -0,2 +1,3 @@ | ||
export { GraphQLOptions } from 'apollo-server-core'; | ||
export { ExpressGraphQLOptionsFunction, ExpressHandler, ExpressGraphiQLOptionsFunction, graphqlExpress, graphiqlExpress } from './expressApollo'; | ||
export { graphqlConnect, graphiqlConnect } from './connectApollo'; |
{ | ||
"name": "apollo-server-express", | ||
"version": "1.3.2", | ||
"version": "1.3.3", | ||
"description": "Production-ready Node.js GraphQL server for Express and Connect", | ||
@@ -29,4 +29,4 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"apollo-server-core": "^1.3.2", | ||
"apollo-server-module-graphiql": "^1.3.0" | ||
"apollo-server-core": "^1.3.3", | ||
"apollo-server-module-graphiql": "^1.3.3" | ||
}, | ||
@@ -36,10 +36,10 @@ "devDependencies": { | ||
"@types/connect": "3.4.31", | ||
"@types/express": "4.0.39", | ||
"@types/graphql": "0.11.7", | ||
"@types/express": "4.11.1", | ||
"@types/graphql": "0.12.6", | ||
"@types/multer": "1.3.6", | ||
"apollo-server-integration-testsuite": "^1.3.2", | ||
"apollo-server-integration-testsuite": "^1.3.3", | ||
"body-parser": "1.18.2", | ||
"connect": "3.6.5", | ||
"connect": "3.6.6", | ||
"connect-query": "1.0.0", | ||
"express": "4.16.2", | ||
"express": "4.16.3", | ||
"multer": "1.3.0" | ||
@@ -46,0 +46,0 @@ }, |
@@ -59,3 +59,2 @@ --- | ||
Anyone is welcome to contribute to GraphQL Server, just read [CONTRIBUTING.md](https://github.com/apollographql/apollo-server/blob/master/CONTRIBUTING.md), take a look at the [roadmap](https://github.com/apollographql/apollo-server/blob/master/ROADMAP.md) and make your first PR! |
@@ -39,3 +39,3 @@ // tslint:disable | ||
GraphQLError, | ||
BREAK | ||
BREAK, | ||
} from 'graphql'; | ||
@@ -50,10 +50,12 @@ | ||
who: { | ||
type: GraphQLString | ||
} | ||
type: GraphQLString, | ||
}, | ||
}, | ||
resolve: (root, args) => 'Hello ' + (args['who'] || 'World') | ||
resolve: (root, args) => 'Hello ' + (args['who'] || 'World'), | ||
}, | ||
thrower: { | ||
type: new GraphQLNonNull(GraphQLString), | ||
resolve: () => { throw new Error('Throws!'); } | ||
resolve: () => { | ||
throw new Error('Throws!'); | ||
}, | ||
}, | ||
@@ -74,4 +76,4 @@ custom: { | ||
}), | ||
} | ||
} | ||
}, | ||
}, | ||
}, | ||
@@ -81,4 +83,4 @@ context: { | ||
resolve: (obj, args, context) => context, | ||
} | ||
} | ||
}, | ||
}, | ||
}); | ||
@@ -93,6 +95,6 @@ | ||
type: QueryRootType, | ||
resolve: () => ({}) | ||
} | ||
} | ||
}) | ||
resolve: () => ({}), | ||
}, | ||
}, | ||
}), | ||
}); | ||
@@ -102,3 +104,3 @@ | ||
return p.then( | ||
(res) => { | ||
res => { | ||
// workaround for unknown issues with testing against npm package of express-graphql. | ||
@@ -116,3 +118,3 @@ // the same code works when testing against the source, I'm not sure why. | ||
return error; | ||
} | ||
}, | ||
); | ||
@@ -123,3 +125,3 @@ } | ||
return new Promise((resolve, reject) => { | ||
fn((error, result) => error ? reject(error) : resolve(result)); | ||
fn((error, result) => (error ? reject(error) : resolve(result))); | ||
}); | ||
@@ -129,3 +131,2 @@ } | ||
describe('test harness', () => { | ||
it('expects to catch errors', async () => { | ||
@@ -148,3 +149,5 @@ let caught; | ||
} | ||
expect(caught && caught.message).to.equal('Expected error to be instanceof Error.'); | ||
expect(caught && caught.message).to.equal( | ||
'Expected error to be instanceof Error.', | ||
); | ||
}); | ||
@@ -168,3 +171,2 @@ | ||
}); | ||
}); | ||
@@ -176,3 +178,2 @@ | ||
describe('POST functionality', () => { | ||
it('allows gzipped POST bodies', async () => { | ||
@@ -182,5 +183,8 @@ const app = express(); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress(() => ({ | ||
schema: TestSchema | ||
}))); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress(() => ({ | ||
schema: TestSchema, | ||
})), | ||
); | ||
@@ -190,3 +194,5 @@ const data = { query: '{ test(who: "World") }' }; | ||
// TODO had to write "as any as Buffer" to make tsc accept it. Does it matter? | ||
const gzippedJson = await promiseTo(cb => zlib.gzip(json as any as Buffer, cb)); | ||
const gzippedJson = await promiseTo(cb => | ||
zlib.gzip((json as any) as Buffer, cb), | ||
); | ||
@@ -202,4 +208,4 @@ const req = request(app) | ||
data: { | ||
test: 'Hello World' | ||
} | ||
test: 'Hello World', | ||
}, | ||
}); | ||
@@ -212,5 +218,8 @@ }); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress(() => ({ | ||
schema: TestSchema | ||
}))); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress(() => ({ | ||
schema: TestSchema, | ||
})), | ||
); | ||
@@ -220,3 +229,5 @@ const data = { query: '{ test(who: "World") }' }; | ||
// TODO had to write "as any as Buffer" to make tsc accept it. Does it matter? | ||
const deflatedJson = await promiseTo(cb => zlib.deflate(json as any as Buffer, cb)); | ||
const deflatedJson = await promiseTo(cb => | ||
zlib.deflate((json as any) as Buffer, cb), | ||
); | ||
@@ -232,4 +243,4 @@ const req = request(app) | ||
data: { | ||
test: 'Hello World' | ||
} | ||
test: 'Hello World', | ||
}, | ||
}); | ||
@@ -248,4 +259,4 @@ }); | ||
originalname: { type: GraphQLString }, | ||
mimetype: { type: GraphQLString } | ||
} | ||
mimetype: { type: GraphQLString }, | ||
}, | ||
}); | ||
@@ -257,4 +268,4 @@ | ||
fields: { | ||
test: { type: GraphQLString } | ||
} | ||
test: { type: GraphQLString }, | ||
}, | ||
}), | ||
@@ -271,6 +282,6 @@ mutation: new GraphQLObjectType({ | ||
return rootValue.request.file; | ||
} | ||
} | ||
} | ||
}) | ||
}, | ||
}, | ||
}, | ||
}), | ||
}); | ||
@@ -286,17 +297,23 @@ | ||
// be accessible from within Schema resolve functions. | ||
app.use('/graphql', graphqlExpress(req => { | ||
return { | ||
schema: TestMutationSchema, | ||
rootValue: { request: req } | ||
}; | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress(req => { | ||
return { | ||
schema: TestMutationSchema, | ||
rootValue: { request: req }, | ||
}; | ||
}), | ||
); | ||
const req = request(app) | ||
.post('/graphql') | ||
.field('query', `mutation TestMutation { | ||
.field( | ||
'query', | ||
`mutation TestMutation { | ||
uploadFile { originalname, mimetype } | ||
}`) | ||
}`, | ||
) | ||
.attach('file', __filename); | ||
return req.then((response) => { | ||
return req.then(response => { | ||
expect(JSON.parse(response.text)).to.deep.equal({ | ||
@@ -306,5 +323,5 @@ data: { | ||
originalname: 'apolloServerHttp.test.js', | ||
mimetype: 'application/javascript' | ||
} | ||
} | ||
mimetype: 'application/javascript', | ||
}, | ||
}, | ||
}); | ||
@@ -320,5 +337,8 @@ }); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
schema: TestSchema | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
}), | ||
); | ||
@@ -335,7 +355,9 @@ const response = await request(app) | ||
data: null, | ||
errors: [ { | ||
message: 'Throws!', | ||
locations: [ { line: 1, column: 2 } ], | ||
path:["thrower"] | ||
} ] | ||
errors: [ | ||
{ | ||
message: 'Throws!', | ||
locations: [{ line: 1, column: 2 }], | ||
path: ['thrower'], | ||
}, | ||
], | ||
}); | ||
@@ -348,5 +370,8 @@ }); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
schema: TestSchema | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
}), | ||
); | ||
@@ -361,6 +386,8 @@ const response = await request(app) | ||
expect(JSON.parse(response.text)).to.deep.equal({ | ||
errors: [ { | ||
message: 'Cannot query field \"notExists\" on type \"QueryRoot\".', | ||
locations: [ { line: 1, column: 2 } ], | ||
} ] | ||
errors: [ | ||
{ | ||
message: 'Cannot query field "notExists" on type "QueryRoot".', | ||
locations: [{ line: 1, column: 2 }], | ||
}, | ||
], | ||
}); | ||
@@ -372,15 +399,22 @@ }); | ||
app.use('/graphql', require('connect-query')(), graphqlExpress({ | ||
schema: TestSchema | ||
})); | ||
app.use( | ||
'/graphql', | ||
require('connect-query')(), | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
}), | ||
); | ||
const response = await request(app) | ||
.get('/graphql').query({ query: '{notExists}' }); | ||
.get('/graphql') | ||
.query({ query: '{notExists}' }); | ||
expect(response.status).to.equal(400); | ||
expect(JSON.parse(response.text)).to.deep.equal({ | ||
errors: [ { | ||
message: 'Cannot query field \"notExists\" on type \"QueryRoot\".', | ||
locations: [ { line: 1, column: 2 } ], | ||
} ] | ||
errors: [ | ||
{ | ||
message: 'Cannot query field "notExists" on type "QueryRoot".', | ||
locations: [{ line: 1, column: 2 }], | ||
}, | ||
], | ||
}); | ||
@@ -393,5 +427,8 @@ }); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
schema: TestSchema | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
}), | ||
); | ||
@@ -411,8 +448,11 @@ const response = await request(app) | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
schema: TestSchema, | ||
formatError(error) { | ||
return { message: 'Custom error format: ' + error.message }; | ||
} | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
formatError(error) { | ||
return { message: 'Custom error format: ' + error.message }; | ||
}, | ||
}), | ||
); | ||
@@ -428,5 +468,7 @@ const response = await request(app) | ||
data: null, | ||
errors: [ { | ||
message: 'Custom error format: Throws!', | ||
} ] | ||
errors: [ | ||
{ | ||
message: 'Custom error format: Throws!', | ||
}, | ||
], | ||
}); | ||
@@ -439,12 +481,15 @@ }); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
schema: TestSchema, | ||
formatError(error) { | ||
return { | ||
message: error.message, | ||
locations: error.locations, | ||
stack: 'Stack trace' | ||
}; | ||
} | ||
})); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
formatError(error) { | ||
return { | ||
message: error.message, | ||
locations: error.locations, | ||
stack: 'Stack trace', | ||
}; | ||
}, | ||
}), | ||
); | ||
@@ -460,7 +505,9 @@ const response = await request(app) | ||
data: null, | ||
errors: [ { | ||
message: 'Throws!', | ||
locations: [ { line: 1, column: 2 } ], | ||
stack: 'Stack trace', | ||
} ] | ||
errors: [ | ||
{ | ||
message: 'Throws!', | ||
locations: [{ line: 1, column: 2 }], | ||
stack: 'Stack trace', | ||
}, | ||
], | ||
}); | ||
@@ -476,7 +523,10 @@ }); | ||
const response = await request(app) | ||
.put('/graphql').query({ query: '{test}' }); | ||
.put('/graphql') | ||
.query({ query: '{test}' }); | ||
expect(response.status).to.equal(405); | ||
expect(response.headers.allow).to.equal('GET, POST'); | ||
return expect(response.text).to.contain('Apollo Server supports only GET/POST requests.'); | ||
return expect(response.text).to.contain( | ||
'Apollo Server supports only GET/POST requests.', | ||
); | ||
}); | ||
@@ -486,39 +536,41 @@ }); | ||
describe('Custom validation rules', () => { | ||
const AlwaysInvalidRule = function (context) { | ||
return { | ||
enter() { | ||
context.reportError(new GraphQLError( | ||
'AlwaysInvalidRule was really invalid!' | ||
)); | ||
return BREAK; | ||
} | ||
}; | ||
const AlwaysInvalidRule = function(context) { | ||
return { | ||
enter() { | ||
context.reportError( | ||
new GraphQLError('AlwaysInvalidRule was really invalid!'), | ||
); | ||
return BREAK; | ||
}, | ||
}; | ||
}; | ||
it('Do not execute a query if it do not pass the custom validation.', async() => { | ||
const app = express(); | ||
it('Do not execute a query if it do not pass the custom validation.', async () => { | ||
const app = express(); | ||
app.use('/graphql', bodyParser.json()); | ||
app.use('/graphql', graphqlExpress({ | ||
app.use('/graphql', bodyParser.json()); | ||
app.use( | ||
'/graphql', | ||
graphqlExpress({ | ||
schema: TestSchema, | ||
validationRules: [ AlwaysInvalidRule ], | ||
})); | ||
validationRules: [AlwaysInvalidRule], | ||
}), | ||
); | ||
const response = await request(app) | ||
.post('/graphql') | ||
.send({ | ||
query: '{thrower}', | ||
}) | ||
expect(response.status).to.equal(400); | ||
expect(JSON.parse(response.text)).to.deep.equal({ | ||
errors: [ | ||
{ | ||
message: 'AlwaysInvalidRule was really invalid!' | ||
}, | ||
] | ||
const response = await request(app) | ||
.post('/graphql') | ||
.send({ | ||
query: '{thrower}', | ||
}); | ||
expect(response.status).to.equal(400); | ||
expect(JSON.parse(response.text)).to.deep.equal({ | ||
errors: [ | ||
{ | ||
message: 'AlwaysInvalidRule was really invalid!', | ||
}, | ||
], | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -6,3 +6,6 @@ import * as connect from 'connect'; | ||
import testSuite, { schema as Schema, CreateAppOptions } from 'apollo-server-integration-testsuite'; | ||
import testSuite, { | ||
schema as Schema, | ||
CreateAppOptions, | ||
} from 'apollo-server-integration-testsuite'; | ||
@@ -16,7 +19,7 @@ function createConnectApp(options: CreateAppOptions = {}) { | ||
} | ||
if (options.graphiqlOptions ) { | ||
app.use('/graphiql', graphiqlConnect( options.graphiqlOptions )); | ||
if (options.graphiqlOptions) { | ||
app.use('/graphiql', graphiqlConnect(options.graphiqlOptions)); | ||
} | ||
app.use('/graphql', require('connect-query')()); | ||
app.use('/graphql', graphqlConnect( options.graphqlOptions )); | ||
app.use('/graphql', graphqlConnect(options.graphqlOptions)); | ||
return app; | ||
@@ -23,0 +26,0 @@ } |
import * as express from 'express'; | ||
import * as bodyParser from 'body-parser'; | ||
import { graphqlExpress, graphiqlExpress } from './expressApollo'; | ||
import testSuite, { schema as Schema, CreateAppOptions } from 'apollo-server-integration-testsuite'; | ||
import testSuite, { | ||
schema as Schema, | ||
CreateAppOptions, | ||
} from 'apollo-server-integration-testsuite'; | ||
import { expect } from 'chai'; | ||
@@ -16,7 +19,7 @@ import { GraphQLOptions } from 'apollo-server-core'; | ||
} | ||
if (options.graphiqlOptions ) { | ||
app.use('/graphiql', graphiqlExpress( options.graphiqlOptions )); | ||
if (options.graphiqlOptions) { | ||
app.use('/graphiql', graphiqlExpress(options.graphiqlOptions)); | ||
} | ||
app.use('/graphql', require('connect-query')()); | ||
app.use('/graphql', graphqlExpress( options.graphqlOptions )); | ||
app.use('/graphql', graphqlExpress(options.graphqlOptions)); | ||
return app; | ||
@@ -26,9 +29,12 @@ } | ||
describe('expressApollo', () => { | ||
it('throws error if called without schema', function(){ | ||
expect(() => graphqlExpress(undefined as GraphQLOptions)).to.throw('Apollo Server requires options.'); | ||
it('throws error if called without schema', function() { | ||
expect(() => graphqlExpress(undefined as GraphQLOptions)).to.throw( | ||
'Apollo Server requires options.', | ||
); | ||
}); | ||
it('throws an error if called with more than one argument', function(){ | ||
expect(() => (<any>graphqlExpress)({}, 'x')).to.throw( | ||
'Apollo Server expects exactly one argument, got 2'); | ||
it('throws an error if called with more than one argument', function() { | ||
expect(() => (<any>graphqlExpress)({}, 'x')).to.throw( | ||
'Apollo Server expects exactly one argument, got 2', | ||
); | ||
}); | ||
@@ -35,0 +41,0 @@ }); |
import * as express from 'express'; | ||
import * as url from 'url'; | ||
import { GraphQLOptions, HttpQueryError, runHttpQuery } from 'apollo-server-core'; | ||
import { | ||
GraphQLOptions, | ||
HttpQueryError, | ||
runHttpQuery, | ||
} from 'apollo-server-core'; | ||
import * as GraphiQL from 'apollo-server-module-graphiql'; | ||
export interface ExpressGraphQLOptionsFunction { | ||
(req?: express.Request, res?: express.Response): GraphQLOptions | Promise<GraphQLOptions>; | ||
(req?: express.Request, res?: express.Response): | ||
| GraphQLOptions | ||
| Promise<GraphQLOptions>; | ||
} | ||
@@ -19,3 +25,5 @@ | ||
export function graphqlExpress(options: GraphQLOptions | ExpressGraphQLOptionsFunction): ExpressHandler { | ||
export function graphqlExpress( | ||
options: GraphQLOptions | ExpressGraphQLOptionsFunction, | ||
): ExpressHandler { | ||
if (!options) { | ||
@@ -27,3 +35,5 @@ throw new Error('Apollo Server requires options.'); | ||
// TODO: test this | ||
throw new Error(`Apollo Server expects exactly one argument, got ${arguments.length}`); | ||
throw new Error( | ||
`Apollo Server expects exactly one argument, got ${arguments.length}`, | ||
); | ||
} | ||
@@ -36,22 +46,25 @@ | ||
query: req.method === 'POST' ? req.body : req.query, | ||
}).then((gqlResponse) => { | ||
res.setHeader('Content-Type', 'application/json'); | ||
res.setHeader('Content-Length', Buffer.byteLength(gqlResponse, 'utf8')); | ||
res.write(gqlResponse); | ||
res.end(); | ||
}, (error: HttpQueryError) => { | ||
if ( 'HttpQueryError' !== error.name ) { | ||
return next(error); | ||
} | ||
}).then( | ||
gqlResponse => { | ||
res.setHeader('Content-Type', 'application/json'); | ||
res.setHeader('Content-Length', Buffer.byteLength(gqlResponse, 'utf8')); | ||
res.write(gqlResponse); | ||
res.end(); | ||
}, | ||
(error: HttpQueryError) => { | ||
if ('HttpQueryError' !== error.name) { | ||
return next(error); | ||
} | ||
if ( error.headers ) { | ||
Object.keys(error.headers).forEach((header) => { | ||
res.setHeader(header, error.headers[header]); | ||
}); | ||
} | ||
if (error.headers) { | ||
Object.keys(error.headers).forEach(header => { | ||
res.setHeader(header, error.headers[header]); | ||
}); | ||
} | ||
res.statusCode = error.statusCode; | ||
res.write(error.message); | ||
res.end(); | ||
}); | ||
res.statusCode = error.statusCode; | ||
res.write(error.message); | ||
res.end(); | ||
}, | ||
); | ||
}; | ||
@@ -61,3 +74,5 @@ } | ||
export interface ExpressGraphiQLOptionsFunction { | ||
(req?: express.Request): GraphiQL.GraphiQLData | Promise<GraphiQL.GraphiQLData>; | ||
(req?: express.Request): | ||
| GraphiQL.GraphiQLData | ||
| Promise<GraphiQL.GraphiQLData>; | ||
} | ||
@@ -76,11 +91,16 @@ | ||
export function graphiqlExpress(options: GraphiQL.GraphiQLData | ExpressGraphiQLOptionsFunction) { | ||
export function graphiqlExpress( | ||
options: GraphiQL.GraphiQLData | ExpressGraphiQLOptionsFunction, | ||
) { | ||
return (req: express.Request, res: express.Response, next) => { | ||
const query = req.url && url.parse(req.url, true).query; | ||
GraphiQL.resolveGraphiQLString(query, options, req).then(graphiqlString => { | ||
res.setHeader('Content-Type', 'text/html'); | ||
res.write(graphiqlString); | ||
res.end(); | ||
}, error => next(error)); | ||
GraphiQL.resolveGraphiQLString(query, options, req).then( | ||
graphiqlString => { | ||
res.setHeader('Content-Type', 'text/html'); | ||
res.write(graphiqlString); | ||
res.end(); | ||
}, | ||
error => next(error), | ||
); | ||
}; | ||
} |
@@ -0,1 +1,5 @@ | ||
// Expose types which can be used by both middleware flavors. | ||
export { GraphQLOptions } from 'apollo-server-core'; | ||
// Express Middleware | ||
export { | ||
@@ -9,5 +13,3 @@ ExpressGraphQLOptionsFunction, | ||
export { | ||
graphqlConnect, | ||
graphiqlConnect, | ||
} from './connectApollo'; | ||
// Connect Middleware | ||
export { graphqlConnect, graphiqlConnect } from './connectApollo'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
29828
725
0
60