Merge branch 'master' into defer-support

This commit is contained in:
Jesse Rosenberger 2018-09-10 13:52:08 +03:00
commit a35529a376
No known key found for this signature in database
GPG key ID: C0CCCF81AA6C08D8
112 changed files with 20273 additions and 1084 deletions

View file

@ -13,8 +13,8 @@ run_install_desired_npm: &run_install_desired_npm
# use that to work-around the issue. It's possible that npm cleanup might # use that to work-around the issue. It's possible that npm cleanup might
# prevent this from being necessary, but this installation can be switched # prevent this from being necessary, but this installation can be switched
# to use `npm` (rather than `yarn`) once Node 6 is no longer tested below. # to use `npm` (rather than `yarn`) once Node 6 is no longer tested below.
name: Install npm@5, but with yarn. name: Install npm@6, but with yarn.
command: sudo yarn global add npm@5 command: sudo yarn global add npm@6
# These are the steps used for each version of Node which we're testing # These are the steps used for each version of Node which we're testing
# against. Thanks to YAMLs inability to merge arrays (though it is able # against. Thanks to YAMLs inability to merge arrays (though it is able
@ -25,39 +25,43 @@ common_test_steps: &common_test_steps
steps: steps:
- *run_install_desired_npm - *run_install_desired_npm
- checkout - checkout
- run: cat ./packages/*/package.json > package-checksum
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "package-checksum" }} keys:
# When lock file changes, use increasingly general patterns to restore cache
- npm-v2-{{ .Branch }}-{{ checksum "package-lock.json" }}
- npm-v2-{{ .Branch }}-
- npm-v2-
- run: npm --version - run: npm --version
- run: npm install - run: npm ci
- save_cache: - save_cache:
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "package-checksum" }} key: npm-v2-{{ .Branch }}-{{ checksum "package-lock.json" }}
paths: paths:
- ./node_modules # This should cache the npm cache instead of node_modules, which is needed because
- run: npm run circle # npm ci actually removes node_modules before installing to guarantee a clean slate.
- ~/.npm
- run: npm run test:ci
# Important! When adding a new job to `jobs`, make sure to define when it # Important! When adding a new job to `jobs`, make sure to define when it
# executes by also adding it to the `workflows` section below! # executes by also adding it to the `workflows` section below!
jobs: jobs:
# Platform tests, each with the same tests but different platform or version. # Platform tests, each with the same tests but different platform or version.
# The docker tag represents the Node.js version and the full list is available # The docker tag represents the Node.js version and the full list is available
# at https://hub.docker.com/r/circleci/node/. # at https://hub.docker.com/r/circleci/node/.
Node.js 6: Node.js 6:
docker: [ { image: 'circleci/node:6' } ] docker: [{ image: 'circleci/node:6' }]
<<: *common_test_steps <<: *common_test_steps
Node.js 8: Node.js 8:
docker: [ { image: 'circleci/node:8' } ] docker: [{ image: 'circleci/node:8' }]
<<: *common_test_steps <<: *common_test_steps
Node.js 10: Node.js 10:
docker: [ { image: 'circleci/node:10' } ] docker: [{ image: 'circleci/node:10' }]
<<: *common_test_steps <<: *common_test_steps
# Other tests, unrelated to typical code tests. # Other tests, unrelated to typical code tests.
Linting: Linting:
docker: [ { image: 'circleci/node:8' } ] docker: [{ image: 'circleci/node:8' }]
steps: steps:
# (speed) Intentionally omitted, unnecessary, run_install_desired_npm. # (speed) Intentionally omitted, unnecessary, run_install_desired_npm.
- checkout - checkout
@ -65,7 +69,7 @@ jobs:
- run: npm install --ignore-scripts - run: npm install --ignore-scripts
- run: npm run lint - run: npm run lint
Docs: Docs:
docker: [ { image: 'circleci/node:8' } ] docker: [{ image: 'circleci/node:8' }]
steps: steps:
# (speed) Intentionally omitted, unnecessary, run_install_desired_npm. # (speed) Intentionally omitted, unnecessary, run_install_desired_npm.
- checkout - checkout

3
.gitignore vendored
View file

@ -36,9 +36,6 @@ typings
.node_repl_history .node_repl_history
.dist .dist
# We don't commit lock files currently
package-lock.json
# Directly ignore this file here, rather than the /docs/ directory's .gitignore # Directly ignore this file here, rather than the /docs/ directory's .gitignore
# so it will be ignored by Prettier, which only supports a single, top-level, # so it will be ignored by Prettier, which only supports a single, top-level,
# ignore file. # ignore file.

3
.prettierignore Normal file
View file

@ -0,0 +1,3 @@
*.json
*.md
*.snap

10
.vscode/settings.json vendored
View file

@ -1,13 +1,11 @@
// Place your settings in this file to overwrite default and user settings. // Place your settings in this file to overwrite default and user settings.
{ {
"editor.tabSize": 2, "editor.tabSize": 2,
"editor.rulers": [110], "editor.rulers": [80],
"editor.wordWrapColumn": 80,
"editor.formatOnSave": true,
"files.trimTrailingWhitespace": true, "files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"editor.wordWrapColumn": 110,
"editor.formatOnSave": true,
"prettier.singleQuote": true,
"prettier.printWidth": 110,
"files.exclude": { "files.exclude": {
"**/.git": true, "**/.git": true,
"**/.DS_Store": true, "**/.DS_Store": true,
@ -16,5 +14,5 @@
"coverage": true, "coverage": true,
"coverage.lcov": true "coverage.lcov": true
}, },
"typescript.tsdk": "node_modules/typescript/lib" "typescript.tsdk": "./node_modules/typescript/lib"
} }

View file

@ -4,10 +4,51 @@ All of the packages in the `apollo-server` repo are released with the same versi
### vNEXT ### vNEXT
- Core: Allow context to be passed to all GraphQLExtension methods. [PR #1547](https://github.com/apollographql/apollo-server/pull/1547)
- Add support for @defer [#1287](https://github.com/apollographql/apollo-server/pull/1287)
### v2.0.7
- Fix [#1581](https://github.com/apollographql/apollo-server/issues/1581) `apollo-server-micro` top level error response [#1619](https://github.com/apollographql/apollo-server/pull/1619)
- Switch `ApolloServerBase.schema` from private access to protected access. [#1610](https://github.com/apollographql/apollo-server/pull/1610)
- Add toggle for including error messages in reports [#1615](https://github.com/apollographql/apollo-server/pull/1615)
- Fix `apollo-server-cloud-functions` tests [#1611](https://github.com/apollographql/apollo-server/pull/1611/)
### v2.0.6
- Update `graphql-playground-html` to 1.7.4 [#1586](https://github.com/apollographql/apollo-server/pull/1586)
- Add support for `graphql-js` v14 by augmenting typeDefs with the `@cacheControl` directive so SDL validation doesn't fail [#1595](https://github.com/apollographql/apollo-server/pull/1595)
- Add `node-fetch` extensions typing to `RequestInit` [#1602](https://github.com/apollographql/apollo-server/pull/1602)
### v2.0.5
- Google Cloud Function support [#1402](https://github.com/apollographql/apollo-server/issues/1402) [#1446](https://github.com/apollographql/apollo-server/pull/1446)
- Switch to a fork of `apollo-upload-server` to fix missing `core-js` dependency. [#1556](https://github.com/apollographql/apollo-server/pull/1556)
### v2.0.4
- apollo-server: Release due to failed build and install
### v2.0.3
- apollo-server: failed publish
- pass payload into context function for subscriptions [#1513](https://github.com/apollographql/apollo-server/pull/1513)
- Add option to mock the entire schema(i.e. sets preserveResolvers) [PR #1546](https://github.com/apollographql/apollo-server/pull/1546)
### v2.0.2
- Release with Lerna 3 due
- Hapi: Allow additional route options to be passed to Hapi.js plugin. [PR #1384](https://github.com/apollographql/apollo-server/pull/1384)
- express, koa: remove next after playground [#1436](https://github.com/apollographql/apollo-server/pull/1436) - express, koa: remove next after playground [#1436](https://github.com/apollographql/apollo-server/pull/1436)
- Hapi: Pass the response toolkit to the context function. [#1407](https://github.com/apollographql/apollo-server/pull/1407) - Hapi: Pass the response toolkit to the context function. [#1407](https://github.com/apollographql/apollo-server/pull/1407)
- update apollo-engine-reporting-protobuf to non-beta [#1429](https://github.com/apollographql/apollo-server/pull/1429) - update apollo-engine-reporting-protobuf to non-beta [#1429](https://github.com/apollographql/apollo-server/pull/1429)
- Add support for @defer [#1287](https://github.com/apollographql/apollo-server/pull/1287) - playground would use its own settings as default [#1516](https://github.com/apollographql/apollo-server/pull/1516)
- Lambda: Look in event.path first when picking endpoint for GraphQL Playground [#1527](https://github.com/apollographql/apollo-server/pull/1527)
- Fix to allow enabling GraphQL Playground in production with custom config [#1495](https://github.com/apollographql/apollo-server/pull/1495)
### v2.0.1
- Bad build due to Lerna 2 release
### rc.10 ### rc.10

View file

@ -52,6 +52,33 @@ const server = new ApolloServer({
}); });
``` ```
While we recommend the use [schema-definition language (SDL)](https://www.apollographql.com/docs/apollo-server/essentials/schema.html#sdl) for defining a GraphQL schema since we feel it's more human-readable and language-agnostic, Apollo Server can be configured with a `GraphQLSchema` object:
```js
const { ApolloServer, gql } = require('apollo-server');
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql');
// The GraphQL schema
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
hello: {
type: GraphQLString,
description: 'A simple type for getting started!',
resolve: () => 'world',
},
},
}),
});
const server = new ApolloServer({ schema });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
```
## Integrations ## Integrations
Often times, Apollo Server needs to be run with a particular integration. To start, run `npm install --save apollo-server-<integration>` where `<integration>` is one of the following: Often times, Apollo Server needs to be run with a particular integration. To start, run `npm install --save apollo-server-<integration>` where `<integration>` is one of the following:

View file

@ -19,7 +19,7 @@ interface FetchMock extends jest.Mock<typeof fetch> {
mockJSONResponseOnce(data?: object, headers?: HeadersInit); mockJSONResponseOnce(data?: object, headers?: HeadersInit);
} }
const mockFetch = jest.fn<typeof fetch>() as FetchMock; const mockFetch = jest.fn<typeof fetch>(fetch) as FetchMock;
mockFetch.mockResponseOnce = ( mockFetch.mockResponseOnce = (
data?: BodyInit, data?: BodyInit,

6117
docs/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
"hexo-renderer-ejs": "0.3.1", "hexo-renderer-ejs": "0.3.1",
"hexo-renderer-less": "0.2.0", "hexo-renderer-less": "0.2.0",
"hexo-renderer-marked": "0.3.2", "hexo-renderer-marked": "0.3.2",
"hexo-server": "0.3.2", "hexo-server": "0.3.3",
"meteor-theme-hexo": "1.0.16" "meteor-theme-hexo": "1.0.16"
}, },
"scripts": { "scripts": {

View file

@ -57,13 +57,17 @@ new ApolloServer({
A boolean enabling the default mocks or object that contains definitions A boolean enabling the default mocks or object that contains definitions
* `mockEntireSchema`: <`Boolean`>
A boolean controlling whether existing resolvers are overridden by mocks. Defaults to true, meaning that all resolvers receive mocked values.
* `schemaDirectives`: <`Object`> * `schemaDirectives`: <`Object`>
Contains definition of schema directives used in the `typeDefs` Contains definition of schema directives used in the `typeDefs`
* `introspection`: <`Boolean`> * `introspection`: <`Boolean`>
Enables and disables schema introspection Enables and disables schema introspection. Disabled in production by default.
* `playground`: <`Boolean`> | <`Object`> * `playground`: <`Boolean`> | <`Object`>
@ -340,3 +344,7 @@ addMockFunctionsToSchema({
itself. Set this to false to disable. You can manually invoke 'stop()' and itself. Set this to false to disable. You can manually invoke 'stop()' and
'sendReport()' on other signals if you'd like. Note that 'sendReport()' 'sendReport()' on other signals if you'd like. Note that 'sendReport()'
does not run synchronously so it cannot work usefully in an 'exit' handler. does not run synchronously so it cannot work usefully in an 'exit' handler.
* `maskErrorDetails`: boolean
Set to true to remove error details from the traces sent to Apollo's servers. Defaults to false.

View file

@ -207,4 +207,4 @@ The friends and families request will return at the same time so when we select
Horizontal scaling is a fantastic way to increase the amount of load that our servers can handle without having to purchase more expensive computing resources to handling it. Apollo Server can scale extremely well like this as long as a couple of concerns are handled: Horizontal scaling is a fantastic way to increase the amount of load that our servers can handle without having to purchase more expensive computing resources to handling it. Apollo Server can scale extremely well like this as long as a couple of concerns are handled:
- Every request should ensure it has access to the required data source. If we are building on top of a HTTP endpoint this isn't a problem, but when using a database it is a good practice to verify our connection on each request. This helps to make our app more fault tolerant and easily scale up a new service which will connect as soon as requests start! - Every request should ensure it has access to the required data source. If we are building on top of a HTTP endpoint this isn't a problem, but when using a database it is a good practice to verify our connection on each request. This helps to make our app more fault tolerant and easily scale up a new service which will connect as soon as requests start!
- Any state should be saved into a shared stateful datastore like redis. By sharing state, we can easily add more and more servers into our infrastructure without fear of loosing any kind of state between scale up and scale down. - Any state should be saved into a shared stateful datastore like redis. By sharing state, we can easily add more and more servers into our infrastructure without fear of losing any kind of state between scale up and scale down.

View file

@ -16,6 +16,12 @@ Therefore, Apollo Server introspection is automatically disabled when the `NODE_
Of course, no system should rely solely on so-called "security through obscurity" and this practice should be combined with other security techniques like open security and security by design. Of course, no system should rely solely on so-called "security through obscurity" and this practice should be combined with other security techniques like open security and security by design.
<h2 id="ssl">Securing with SSL/TLS</h2>
You can secure all communication between the clients and your GraphQL server by using SSL/TLS. Apollo Server, with subscriptions, can be configured to use the `https` module with `apollo-server-express`. See [example server code](../essentials/server.html#ssl).
Alternatively, you can use a reverse proxy solution like [NGINX](https://www.nginx.com/) or [Traefik](https://traefik.io/). An additional benefit of using Traefik is that you can use a free [Let's Encrypt SSL certificate](http://niels.nu/blog/2017/traefik-https-letsencrypt.html).
<h2 id="injection">Injection prevention</h2> <h2 id="injection">Injection prevention</h2>
As we build out our schema, it may be tempting to allow for shortcut arguments to creep in which have security risks. This most commonly happens on filters and on mutation inputs: As we build out our schema, it may be tempting to allow for shortcut arguments to creep in which have security risks. This most commonly happens on filters and on mutation inputs:

View file

@ -143,6 +143,62 @@ Hapi follows the same pattern with `apollo-server-express` replaced with `apollo
Apollo Server works great in "serverless" environments such as Amazon Lambda and Microsoft Azure Functions. These implementations have some extra considerations which won't be covered in this guide. Apollo Server works great in "serverless" environments such as Amazon Lambda and Microsoft Azure Functions. These implementations have some extra considerations which won't be covered in this guide.
<h3 id="ssl">SSL/TLS Support</h3>
If you require an HTTPS connection to your Apollo Server, you can use the `https` module with `apollo-server-express`. Subscriptions can also go through an encrypted WSS socket.
Here is an example of using HTTPS in production and HTTP in development, with subscriptions:
```javascript
import express from 'express'
import { ApolloServer } from 'apollo-server-express'
import typeDefs from './graphql/schema'
import resolvers from './graphql/resolvers'
import * as fs from 'fs'
import * as https from 'https'
import * as http from 'http'
const configurations = {
// Note: You may need sudo to run on port 443
production: { ssl: true, port: 443, hostname: 'example.com' },
development: { ssl: false, port: 4000, hostname: 'localhost' }
}
const environment = process.env.NODE_ENV || 'production'
const config = configurations[environment]
const apollo = new ApolloServer({ typeDefs, resolvers })
const app = express()
apollo.applyMiddleware({ app })
// Create the HTTPS or HTTP server, per configuration
var server
if (config.ssl) {
// Assumes certificates are in .ssl folder from package root. Make sure the files
// are secured.
server = https.createServer(
{
key: fs.readFileSync(`./ssl/${environment}/server.key`),
cert: fs.readFileSync(`./ssl/${environment}/server.crt`)
},
app
)
} else {
server = http.createServer(app)
}
// Add subscription support
apollo.installSubscriptionHandlers(server)
server.listen({ port: config.port }, () =>
console.log(
'🚀 Server ready at',
`http${config.ssl ? 's' : ''}://${config.hostname}:${config.port}${apollo.graphqlPath}`
)
)
```
## Next steps ## Next steps
Now that the GraphQL server is running, it's time to dive deeper into how we'll fetch data for our types. We'll get started on that in the [next step](./data.html). Now that the GraphQL server is running, it's time to dive deeper into how we'll fetch data for our types. We'll get started on that in the [next step](./data.html).

View file

@ -143,6 +143,44 @@ const mocks = {
For some more background and flavor on this approach, read the ["Mocking your server with one line of code"](https://medium.com/apollo-stack/mocking-your-server-with-just-one-line-of-code-692feda6e9cd) article on the Apollo blog. For some more background and flavor on this approach, read the ["Mocking your server with one line of code"](https://medium.com/apollo-stack/mocking-your-server-with-just-one-line-of-code-692feda6e9cd) article on the Apollo blog.
### Using existing resolvers with mocks
The default behavior for mocks is to overwrite the resolvers already present in the schema. To keep the existing resolvers, set the `mockEntireSchema` field to false.
```js line=26
const { ApolloServer } = require('apollo-server');
const typeDefs = gql`
type Query {
hello: String
resolved: String
}
`;
const resolvers = {
Query: {
resolved: () => 'Resolved',
},
};
const mocks = {
Int: () => 6,
Float: () => 22.1,
String: () => 'Hello',
};
const server = new ApolloServer({
typeDefs,
resolvers,
mocks,
mockEntireSchema: false,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
});
```
## Mocking a schema using introspection ## Mocking a schema using introspection
The GraphQL specification allows clients to introspect the schema with a [special set of types and fields](https://facebook.github.io/graphql/#sec-Introspection) that every schema must include. The results of a [standard introspection query](https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js) can be used to generate an instance of GraphQLSchema which can be mocked as explained above. The GraphQL specification allows clients to introspect the schema with a [special set of types and fields](https://facebook.github.io/graphql/#sec-Introspection) that every schema must include. The results of a [standard introspection query](https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js) can be used to generate an instance of GraphQLSchema which can be mocked as explained above.

View file

@ -140,6 +140,10 @@ The example above validates the user's token that is sent with the first initial
In case of an authentication error, the Promise will be rejected, which prevents the client's connection. In case of an authentication error, the Promise will be rejected, which prevents the client's connection.
<h2 id="wss">Securing Subscriptions with WSS</h2>
Subscriptions can be configured to over SSL/WSS. See [example server](../essentials/server.html#ssl).
<h2 id="subscription-filters">Subscription Filters</h2> <h2 id="subscription-filters">Subscription Filters</h2>
Sometimes a client will want to filter out specific events based on context and arguments. Sometimes a client will want to filter out specific events based on context and arguments.

View file

@ -10,7 +10,7 @@ In this guide, we'll walk you through the process of creating a GraphQL server i
* Have a basic understanding of the fundamental GraphQL principles. * Have a basic understanding of the fundamental GraphQL principles.
* Be able to send a query to the new GraphQL server and see the response using GraphQL Playground. * Be able to send a query to the new GraphQL server and see the response using GraphQL Playground.
To be successful, make sure you already have general JavaScript knowledge, a recent version of Node.js installed (6+). To be successful, make sure you already have general JavaScript knowledge and a recent version of Node.js installed (6+).
If you want to skip walking through the steps, the [More information](#More-information) section at the bottom has a link to a GitHub repository which can be cloned and run locally, and a Glitch to play around in your browser! If you want to skip walking through the steps, the [More information](#More-information) section at the bottom has a link to a GitHub repository which can be cloned and run locally, and a Glitch to play around in your browser!

View file

@ -5,11 +5,11 @@ description: How to migrate to Apollo Server 2.0
Apollo Server 2.0 dramatically simplifies the API for building a GraphQL server without compromising on features. It's also completely backward compatible, so you don't have to worry about breaking changes when upgrading. Apollo Server 2.0 dramatically simplifies the API for building a GraphQL server without compromising on features. It's also completely backward compatible, so you don't have to worry about breaking changes when upgrading.
While it's possible to migrate an existing server to 2.0 without any changes, we recommend changing to new patterns we're suggesting in order to take advantage of all the latest Apollo Server features, reduce the boilerplate, and enable future flexibility. To learn how to migrate to the 2.0 from version 1.0, please read the following guide. While it's possible to migrate an existing server to 2.0 without any changes, we recommend changing to new patterns we're suggesting in order to take advantage of all the latest Apollo Server features, reduce the boilerplate, and enable future flexibility. To learn how to migrate to 2.0 from version 1.0, please read the following guide.
<h2 id="gql-tag">The `gql` tag</h2> <h2 id="gql-tag">The `gql` tag</h2>
Apollo Server 2.0 ships with the `gql` tag for **editor syntax highlighting** and **auto-formatting** with Prettier. In the future, we will be using it for statically analyzing GraphQL queries, so Apollo Servers requires wrapping your schema with `gql`. Apollo Server 2.0 ships with the `gql` tag for **editor syntax highlighting** and **auto-formatting** with Prettier. In the future, we will be using it for statically analyzing GraphQL queries, so Apollo Server requires wrapping your schema with `gql`.
The `gql` tag parses the query string into an AST and is now exported from the new `apollo-server` package. The `gql` tag parses the query string into an AST and is now exported from the new `apollo-server` package.
@ -48,7 +48,7 @@ Check out the following changes for Apollo Server 2.0.
* You no longer need to import `body-parser` to set up `apollo-server-express`. * You no longer need to import `body-parser` to set up `apollo-server-express`.
* You no longer need to import `makeExecutableSchema` from `graphql-tools`. * You no longer need to import `makeExecutableSchema` from `graphql-tools`.
* You no longer need to import `graphqlExpress` and `graphiqlExpress` from `apollo-server-express`. * You no longer need to import `graphqlExpress` and `graphiqlExpress` from `apollo-server-express`.
* You should pass in `typeDefs` and resolvers as parameters to an instance of Apollo Server. * You should pass in `typeDefs` and `resolvers` as parameters to an instance of Apollo Server.
* If the server is only functioning as a GraphQL server, it's no longer necessary to run your own HTTP server (like `express`). * If the server is only functioning as a GraphQL server, it's no longer necessary to run your own HTTP server (like `express`).
<h2 id="Middleware">Middleware</h2> <h2 id="Middleware">Middleware</h2>
@ -221,6 +221,42 @@ server.listen().then(({ url }) => {
}); });
``` ```
<h3 id="schema-object-notation">Constructing an Executable Schema Manually</h3>
While we recommend the use [schema-definition language (SDL)](https://www.apollographql.com/docs/apollo-server/essentials/schema.html#sdl) for defining a GraphQL schema since we feel it's more human-readable and language-agnostic, Apollo Server 2 also supports schemas which are built with the [`graphql-js`'s `graphql/type` notation](https://graphql.org/graphql-js/type/) by passing a `GraphQLSchema` to the `schema` option of the `ApolloServer` constructor.
For example, using this technique the above schema might be represented and used as:
```js
const {
graphql,
GraphQLSchema,
GraphQLObjectType,
GraphQLString
} = require('graphql');
const { ApolloServer } = require('apollo-server');
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'hello world';
}
}
}
})
});
const server = new ApolloServer({ schema });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
```
<h2 id="request-headers">Accessing Request Headers</h2> <h2 id="request-headers">Accessing Request Headers</h2>
Apollo Server 1 allowed request headers to be used in the construction of the GraphQL options. Apollo Server 2 allows constructor to create the context based upon the request. Apollo Server 1 allowed request headers to be used in the construction of the GraphQL options. Apollo Server 2 allows constructor to create the context based upon the request.

View file

@ -1,18 +1,4 @@
{ {
"lerna": "2.0.0", "packages": ["packages/*"],
"exact": true, "version": "independent"
"version": "independent",
"changelog": {
"repo": "apollographql/apollo-server",
"labels": {
"tag: breaking change": ":boom: Breaking Change",
"tag: new feature": ":rocket: New Feature",
"tag: bug fix": ":bug: Bug Fix",
"tag: polish": ":nail_care: Polish",
"tag: documentation": "Documentation",
"tag: internal": ":house: Internal"
}
},
"hoist": true,
"packages": ["packages/*"]
} }

6
netlify.toml Normal file
View file

@ -0,0 +1,6 @@
[build]
base = "docs/"
publish = "docs/public/"
command = "npm install && npm run build"
[build.environment]
NPM_VERSION = "6"

12689
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
{ {
"name": "apollo-server-monorepo",
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -6,20 +7,20 @@
"url": "git+https://github.com/apollographql/apollo-server.git" "url": "git+https://github.com/apollographql/apollo-server.git"
}, },
"scripts": { "scripts": {
"postinstall": "lerna run prepare",
"compile": "lerna run compile", "compile": "lerna run compile",
"lint": "prettier-check --ignore-path .gitignore \"{docs/{,source/**},.,packages/**,test}/{*.js,*.ts}\"", "lint": "prettier-check --ignore-path .gitignore \"{docs/{,source/**},.,packages/**,test}/{*.js,*.ts}\"",
"lint-fix": "prettier --write --ignore-path .gitignore \"{docs/{,source/**},.,packages/**,test}/{*.js,*.ts}\"", "lint-fix": "prettier --write --ignore-path .gitignore \"{docs/{,source/**},.,packages/**,test}/{*.js,*.ts}\"",
"prebootstrap": "npm install",
"postinstall": "lerna bootstrap",
"pretest": "npm run compile", "pretest": "npm run compile",
"test": "npm run testonly", "test": "npm run testonly",
"posttest": "npm run lint", "posttest": "npm run lint",
"testonly": "lerna run test", "testonly": "jest --verbose",
"coverage": "lerna run coverage", "test:watch": "npm run testonly -- --watch",
"circle": "lerna run coverage && lerna run circle", "test:ci": "npm run testonly -- --ci --maxWorkers=2",
"release": "lerna publish --exact", "release": "npm run clean && npm ci && lerna publish --exact",
"deploy-alpha": "npm run clean && npm ci && lerna publish --exact --scope=apollo-server{,-core,-express,-koa,-hapi,-micro} --npm-tag=alpha",
"precommit": "lint-staged", "precommit": "lint-staged",
"deploy-alpha": "lerna publish --exact --scope=apollo-server{,-core,-express,-koa,-hapi,-micro} --npm-tag=alpha" "clean": "find . -name \"node_modules\" -exec rm -rf '{}' + && find . -name \"dist\" -exec rm -rf '{}' +"
}, },
"lint-staged": { "lint-staged": {
"*.ts": [ "*.ts": [
@ -35,22 +36,110 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "7.0.0-beta.55" "apollo-cache-control": "file:packages/apollo-cache-control",
"apollo-datasource": "file:packages/apollo-datasource",
"apollo-datasource-rest": "file:packages/apollo-datasource-rest",
"apollo-engine-reporting": "file:packages/apollo-engine-reporting",
"apollo-engine-reporting-protobuf": "file:packages/apollo-engine-reporting-protobuf",
"apollo-server": "file:packages/apollo-server",
"apollo-server-cache-memcached": "file:packages/apollo-server-cache-memcached",
"apollo-server-cache-redis": "file:packages/apollo-server-cache-redis",
"apollo-server-caching": "file:packages/apollo-server-caching",
"apollo-server-cloudflare": "file:packages/apollo-server-cloudflare",
"apollo-server-core": "file:packages/apollo-server-core",
"apollo-server-env": "file:packages/apollo-server-env",
"apollo-server-errors": "file:packages/apollo-server-errors",
"apollo-server-express": "file:packages/apollo-server-express",
"apollo-server-hapi": "file:packages/apollo-server-hapi",
"apollo-server-integration-testsuite": "file:packages/apollo-server-integration-testsuite",
"apollo-server-koa": "file:packages/apollo-server-koa",
"apollo-server-lambda": "file:packages/apollo-server-lambda",
"apollo-server-micro": "file:packages/apollo-server-micro",
"apollo-tracing": "file:packages/apollo-tracing",
"graphql-extensions": "file:packages/graphql-extensions"
}, },
"devDependencies": { "devDependencies": {
"@types/graphql": "0.13.3", "@types/async-retry": "1.2.1",
"@types/jest": "23.3.1", "@types/aws-lambda": "8.10.11",
"@types/node": "10.5.5", "@types/body-parser": "1.17.0",
"graphql": "0.13.2", "@types/connect": "3.4.32",
"@types/fibers": "0.0.30",
"@types/graphql": "14.0.0",
"@types/hapi": "17.0.19",
"@types/jest": "23.3.2",
"@types/koa-multer": "1.0.0",
"@types/koa-router": "7.0.31",
"@types/lodash": "4.14.116",
"@types/lru-cache": "4.1.1",
"@types/memcached": "2.2.5",
"@types/micro": "7.3.1",
"@types/multer": "1.3.7",
"@types/node": "10.9.4",
"@types/redis": "2.8.6",
"@types/request": "2.47.1",
"apollo-fetch": "0.7.0",
"apollo-link": "1.2.2",
"apollo-link-http": "1.5.4",
"apollo-link-persisted-queries": "0.2.1",
"body-parser": "1.18.3",
"connect": "3.6.6",
"express": "4.16.3",
"fibers": "3.0.0",
"form-data": "2.3.2",
"graphql": "14.0.2",
"graphql-subscriptions": "0.5.8",
"graphql-tag": "2.9.2",
"graphql-tools": "3.1.1",
"hapi": "17.5.4",
"husky": "0.14.3", "husky": "0.14.3",
"jest": "23.4.2", "jest": "23.5.0",
"jest-matcher-utils": "23.2.0", "jest-matcher-utils": "23.5.0",
"lerna": "2.11.0", "js-sha256": "0.9.0",
"lint-staged": "7.2.0", "koa-multer": "1.0.2",
"prettier": "1.14.0", "lerna": "3.3.0",
"lint-staged": "7.2.2",
"memcached-mock": "0.1.0",
"meteor-promise": "0.8.6",
"mock-req": "0.2.0",
"multer": "1.3.1",
"node-fetch": "2.2.0",
"prettier": "1.14.2",
"prettier-check": "2.0.0", "prettier-check": "2.0.0",
"supertest": "3.1.0", "qs-middleware": "1.0.3",
"ts-jest": "23.1.2", "redis-mock": "0.32.0",
"typescript": "2.9.2" "request": "2.88.0",
"request-promise": "4.2.2",
"subscriptions-transport-ws": "0.9.14",
"supertest": "3.3.0",
"test-listen": "1.1.0",
"ts-jest": "23.1.4",
"tslint": "5.11.0",
"typescript": "3.0.3",
"ws": "6.0.0",
"yup": "0.26.3"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/packages/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"testRegex": "/__tests__/.*\\.test\\.(js|ts)$",
"moduleFileExtensions": [
"ts",
"js"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/dist/"
],
"clearMocks": true,
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -1,16 +1,13 @@
{ {
"name": "apollo-cache-control", "name": "apollo-cache-control",
"version": "0.2.0", "version": "0.2.3",
"description": "A GraphQL extension for cache control", "description": "A GraphQL extension for cache control",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"license": "MIT", "license": "MIT",
"repository": "apollographql/apollo-cache-control-js", "repository": "apollographql/apollo-cache-control-js",
@ -19,38 +16,10 @@
"node": ">=6.0" "node": ">=6.0"
}, },
"dependencies": { "dependencies": {
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"graphql-extensions": "0.1.0" "graphql-extensions": "file:../graphql-extensions"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "0.10.x - 0.13.x" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"devDependencies": {
"graphql-tools": "3.1.1"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -2,16 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-datasource-rest", "name": "apollo-datasource-rest",
"version": "0.1.1", "version": "0.1.5",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,9 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -24,33 +22,10 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"apollo-datasource": "0.1.0", "apollo-datasource": "file:../apollo-datasource",
"apollo-server-caching": "0.1.0", "apollo-server-caching": "file:../apollo-server-caching",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"apollo-server-errors": "2.0.0", "apollo-server-errors": "file:../apollo-server-errors",
"http-cache-semantics": "^4.0.0" "http-cache-semantics": "^4.0.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "apollo-datasource-rest/src/__tests__/.*$",
"roots": [
"../../"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -97,8 +97,14 @@ export class HTTPCache {
let ttlOverride = cacheOptions && cacheOptions.ttl; let ttlOverride = cacheOptions && cacheOptions.ttl;
if (!ttlOverride && !(request.method === 'GET' && policy.storable())) if (
// With a TTL override, only cache succesful responses but otherwise ignore method and response headers
!(ttlOverride && (policy._status >= 200 && policy._status <= 299)) &&
// Without an override, we only cache GET requests and respect standard HTTP cache semantics
!(request.method === 'GET' && policy.storable())
) {
return response; return response;
}
let ttl = ttlOverride || Math.round(policy.timeToLive() / 1000); let ttl = ttlOverride || Math.round(policy.timeToLive() / 1000);
if (ttl <= 0) return response; if (ttl <= 0) return response;

View file

@ -177,6 +177,22 @@ describe('HTTPCache', () => {
expect(response.headers.get('Age')).toEqual('0'); expect(response.headers.get('Age')).toEqual('0');
}); });
it('does not store a response with an overriden TTL and a non-success status code', async () => {
fetch.mockResponseOnce(
'Internal server error',
{ 'Cache-Control': 'max-age=30' },
500,
);
await httpCache.fetch(new Request('https://api.example.com/people/1'), {
cacheOptions: {
ttl: 30,
},
});
expect(store.size).toEqual(0);
});
it('allows overriding the TTL dynamically', async () => { it('allows overriding the TTL dynamically', async () => {
fetch.mockJSONResponseOnce( fetch.mockJSONResponseOnce(
{ name: 'Ada Lovelace' }, { name: 'Ada Lovelace' },

View file

@ -2,16 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-datasource", "name": "apollo-datasource",
"version": "0.1.0", "version": "0.1.3",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,9 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -24,30 +22,7 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"apollo-server-caching": "0.1.0", "apollo-server-caching": "file:../apollo-server-caching",
"apollo-server-env": "2.0.0" "apollo-server-env": "file:../apollo-server-env"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "apollo-datasource-rest/src/__tests__/.*$",
"roots": [
"../../"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -2,16 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,94 +0,0 @@
version: 2
#
# Reusable Snippets!
#
# These are re-used by the various tests below, to avoid repetition.
#
run_install_desired_npm: &run_install_desired_npm
run:
# Due to a bug, npm upgrades from the version of npm that ships with
# Node.js 6 (npm v3.10.10) go poorly and generally cause other problems
# within the environment. Since `yarn` is already available here we can
# use that to work-around the issue. It's possible that `npm` artifact
# jockeying might avoid this need, but this can be removed once Node 6 is
# no longer being built below.
name: Install npm@5, but with yarn.
command: sudo yarn global add npm@5
# These are the steps used for each version of Node which we're testing
# against. Thanks to YAMLs inability to merge arrays (though it is able
# to merge objects), every version of Node must use the exact same steps,
# or these steps would need to be repeated in a version of Node that needs
# something different. Probably best to avoid that, out of principle, though.
common_test_steps: &common_test_steps
steps:
# Install the latest npm, rather than using the versions which ship
# in older versions of Node.js This allows for a more consistent
# installation, and typically users of older Node versions at least
# update their npm to the latest.
- *run_install_desired_npm
- checkout
# Build a cache key which will bust with Node.js ABI and version changes.
- run: |
node -p process.config | tee .cache_key
node -p process.versions | tee -a .cache_key
cat package-lock.json | tee -a .cache_key
- restore_cache:
keys:
- v1-dependencies-{{ checksum ".cache_key" }}
- run: node --version
- run: npm --version
- run: npm install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum ".cache_key" }}
# test with coverage.
- run: npm run circle
jobs:
# Platform tests, each with the same tests but different platform or version.
# The docker tag represents the Node.js version and the full list is available
# at https://hub.docker.com/r/circleci/node/.
Node.js 4:
docker: [ { image: 'circleci/node:4' } ]
<<: *common_test_steps
Node.js 6:
docker: [ { image: 'circleci/node:6' } ]
<<: *common_test_steps
Node.js 8:
docker: [ { image: 'circleci/node:8' } ]
<<: *common_test_steps
Node.js 10:
docker: [ { image: 'circleci/node:10' } ]
<<: *common_test_steps
# Linting can run on the latest Node, which already has the latest `npm` and
# doesn't warrant run_install_desired_npm (which is more critical above)
Linting:
docker: [ { image: 'circleci/node:8' } ]
steps:
# (speed) Intentionally omitted (unnecessary) run_install_desired_npm.
- checkout
- run: npm install
- run: npm run lint
workflows:
version: 2
Build and Test:
jobs:
# There isn't any non-generated code in this package now, so we only
# bother to run one test job and no linting.
- Node.js 10

View file

@ -1,2 +0,0 @@
/dist
/node_modules

View file

@ -1,99 +0,0 @@
{
"name": "apollo-engine-reporting-protobuf",
"version": "0.0.0-beta.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
},
"@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
},
"@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
},
"@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
},
"@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
"requires": {
"@protobufjs/aspromise": "1.1.2",
"@protobufjs/inquire": "1.1.0"
}
},
"@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
},
"@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
},
"@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
},
"@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
},
"@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"@types/node": {
"version": "8.10.16",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.16.tgz",
"integrity": "sha512-KlK7YiZXSY8E6v8E4+cCor9IT071bfZrfYqKf0SEj8SJ0Qk4DEz1sgL02Wt6mebNNM9d7870PEoJRHAsUcJPrw=="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"protobufjs": {
"version": "6.8.6",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.6.tgz",
"integrity": "sha512-eH2OTP9s55vojr3b7NBaF9i4WhWPkv/nq55nznWNp/FomKrLViprUcqnBjHph2tFQ+7KciGPTPsVWGz0SOhL0Q==",
"requires": {
"@protobufjs/aspromise": "1.1.2",
"@protobufjs/base64": "1.1.2",
"@protobufjs/codegen": "2.0.4",
"@protobufjs/eventemitter": "1.1.0",
"@protobufjs/fetch": "1.1.0",
"@protobufjs/float": "1.0.2",
"@protobufjs/inquire": "1.1.0",
"@protobufjs/path": "1.1.2",
"@protobufjs/pool": "1.1.0",
"@protobufjs/utf8": "1.1.0",
"@types/long": "3.0.32",
"@types/node": "8.10.16",
"long": "4.0.0"
},
"dependencies": {
"@types/long": {
"version": "3.0.32",
"resolved": "https://registry.npmjs.org/@types/long/-/long-3.0.32.tgz",
"integrity": "sha512-ZXyOOm83p7X8p3s0IYM3VeueNmHpkk/yMlP8CLeOnEcu6hIwPH7YjZBvhQkR0ZFS2DqZAxKtJ/M5fcuv3OU5BA=="
}
}
}
}
}

View file

@ -1,14 +1,13 @@
{ {
"name": "apollo-engine-reporting-protobuf", "name": "apollo-engine-reporting-protobuf",
"version": "0.0.0-beta.7", "version": "0.0.1",
"description": "Protobuf format for Apollo Engine", "description": "Protobuf format for Apollo Engine",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"prepublish": "npm run pbjs && npm run pbts", "prepare": "npm run pbjs && npm run pbts",
"pbjs": "bash -c 'mkdir -p dist && pbjs --target static-module --out dist/index.js --wrap commonjs --force-number <(grep -v \"package mdg.engine.proto\" reports.proto)'", "pbjs": "bash -c 'mkdir -p dist && pbjs --target static-module --out dist/index.js --wrap commonjs --force-number <(grep -v \"package mdg.engine.proto\" reports.proto)'",
"pbts": "pbts -o dist/index.d.ts dist/index.js", "pbts": "pbts -o dist/index.d.ts dist/index.js"
"circle": "npm run prepublish"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -5,5 +5,5 @@
"outDir": "./dist" "outDir": "./dist"
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,19 +1,15 @@
{ {
"name": "apollo-engine-reporting", "name": "apollo-engine-reporting",
"version": "0.0.0", "version": "0.0.4",
"description": "Send reports about your GraphQL services to Apollo Engine", "description": "Send reports about your GraphQL services to Apollo Engine",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"scripts": { "scripts": {
"circle": "jest --verbose --coverage",
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile",
"lint": "prettier -l 'src/**/*.{ts,js}' && tslint -p tsconfig.json 'src/**/*.ts'", "lint": "prettier -l 'src/**/*.{ts,js}' && tslint -p tsconfig.json 'src/**/*.ts'",
"lint-fix": "prettier --write 'src/**/*.{ts,js}' && tslint --fix -p tsconfig.json 'src/**/*.ts'", "lint-fix": "prettier --write 'src/**/*.{ts,js}' && tslint --fix -p tsconfig.json 'src/**/*.ts'"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"license": "MIT", "license": "MIT",
"repository": "https://github.com/apollographql/apollo-engine-reporting", "repository": "https://github.com/apollographql/apollo-engine-reporting",
@ -22,39 +18,10 @@
"node": ">=6.0" "node": ">=6.0"
}, },
"dependencies": { "dependencies": {
"apollo-engine-reporting-protobuf": "0.0.0-beta.7", "apollo-engine-reporting-protobuf": "file:../apollo-engine-reporting-protobuf",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"async-retry": "^1.2.1", "async-retry": "^1.2.1",
"graphql-extensions": "0.1.0", "graphql-extensions": "file:../graphql-extensions",
"lodash": "^4.17.10" "lodash": "^4.17.10"
},
"devDependencies": {
"@types/async-retry": "1.2.1",
"@types/graphql": "0.13.3",
"@types/lodash": "4.14.116",
"graphql": "0.13.2",
"graphql-tag": "2.9.2",
"graphql-tools": "3.1.1",
"tslint": "5.11.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -60,9 +60,9 @@ export interface EngineReportingOptions {
maxAttempts?: number; maxAttempts?: number;
// Minimum backoff for retries. Defaults to 100ms. // Minimum backoff for retries. Defaults to 100ms.
minimumRetryDelayMs?: number; minimumRetryDelayMs?: number;
// By default, errors sending reports to Engine servers will be logged // By default, errors that occur when sending trace reports to Engine servers
// to standard error. Specify this function to process errors in a different // will be logged to standard error. Specify this function to process errors
// way. // in a different way.
reportErrorFunction?: (err: Error) => void; reportErrorFunction?: (err: Error) => void;
// A case-sensitive list of names of variables whose values should not be sent // A case-sensitive list of names of variables whose values should not be sent
// to Apollo servers, or 'true' to leave out all variables. In the former // to Apollo servers, or 'true' to leave out all variables. In the former
@ -81,6 +81,8 @@ export interface EngineReportingOptions {
handleSignals?: boolean; handleSignals?: boolean;
// Sends the trace report immediately. This options is useful for stateless environments // Sends the trace report immediately. This options is useful for stateless environments
sendReportsImmediately?: boolean; sendReportsImmediately?: boolean;
// To remove the error message from traces, set this to true. Defaults to false
maskErrorDetails?: boolean;
// XXX Provide a way to set client_name, client_version, client_address, // XXX Provide a way to set client_name, client_version, client_address,
// service, and service_version fields. They are currently not revealed in the // service, and service_version fields. They are currently not revealed in the

View file

@ -43,7 +43,10 @@ export class EngineReportingExtension<TContext = any>
options: EngineReportingOptions, options: EngineReportingOptions,
addTrace: (signature: string, operationName: string, trace: Trace) => void, addTrace: (signature: string, operationName: string, trace: Trace) => void,
) { ) {
this.options = options; this.options = {
maskErrorDetails: false,
...options,
};
this.addTrace = addTrace; this.addTrace = addTrace;
const root = new Trace.Node(); const root = new Trace.Node();
this.trace.root = root; this.trace.root = root;
@ -54,7 +57,7 @@ export class EngineReportingExtension<TContext = any>
request: Request; request: Request;
queryString?: string; queryString?: string;
parsedQuery?: DocumentNode; parsedQuery?: DocumentNode;
variables: Record<string, any>; variables?: Record<string, any>;
persistedQueryHit?: boolean; persistedQueryHit?: boolean;
persistedQueryRegister?: boolean; persistedQueryRegister?: boolean;
}): EndHandler { }): EndHandler {
@ -136,7 +139,7 @@ export class EngineReportingExtension<TContext = any>
this.trace.details!.variablesJson![name] = ''; this.trace.details!.variablesJson![name] = '';
} else { } else {
this.trace.details!.variablesJson![name] = JSON.stringify( this.trace.details!.variablesJson![name] = JSON.stringify(
o.variables[name], o.variables![name],
); );
} }
}); });
@ -225,15 +228,19 @@ export class EngineReportingExtension<TContext = any>
node = specificNode; node = specificNode;
} }
} }
node!.error!.push(
new Trace.Error({ // Always send the trace errors, so that the UI acknowledges that there is an error.
message: error.message, const errorInfo = this.options.maskErrorDetails
location: (error.locations || []).map( ? { message: '<masked>' }
({ line, column }) => new Trace.Location({ line, column }), : {
), message: error.message,
json: JSON.stringify(error), location: (error.locations || []).map(
}), ({ line, column }) => new Trace.Location({ line, column }),
); ),
json: JSON.stringify(error),
};
node!.error!.push(new Trace.Error(errorInfo));
}); });
} }
} }

View file

@ -2,16 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1 +0,0 @@
.idea

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-cache-memcached", "name": "apollo-server-cache-memcached",
"version": "0.1.0", "version": "0.1.3",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,9 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -24,32 +22,8 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"apollo-server-caching": "0.1.0", "apollo-server-caching": "file:../apollo-server-caching",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"memcached": "^2.2.2" "memcached": "^2.2.2"
},
"devDependencies": {
"@types/memcached": "2.2.5",
"memcached-mock": "0.1.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -3,17 +3,20 @@ import * as Memcached from 'memcached';
import { promisify } from 'util'; import { promisify } from 'util';
export class MemcachedCache implements KeyValueCache { export class MemcachedCache implements KeyValueCache {
readonly client; // FIXME: Replace any with proper promisified type
readonly client: any;
readonly defaultSetOptions = { readonly defaultSetOptions = {
ttl: 300, ttl: 300,
}; };
constructor(serverLocation: Memcached.Location, options?: Memcached.options) { constructor(serverLocation: Memcached.Location, options?: Memcached.options) {
this.client = new Memcached(serverLocation, options); const client = new Memcached(serverLocation, options);
// promisify client calls for convenience // promisify client calls for convenience
this.client.get = promisify(this.client.get).bind(this.client); client.get = promisify(client.get).bind(client);
this.client.set = promisify(this.client.set).bind(this.client); client.set = promisify(client.set).bind(client);
this.client.flush = promisify(this.client.flush).bind(this.client); client.flush = promisify(client.flush).bind(client);
this.client = client;
} }
async set( async set(

View file

@ -2,15 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1 +0,0 @@
.idea

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-cache-redis", "name": "apollo-server-cache-redis",
"version": "0.1.0", "version": "0.1.3",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,9 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -24,33 +22,9 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"apollo-server-caching": "0.1.0", "apollo-server-caching": "file:../apollo-server-caching",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"dataloader": "^1.4.0", "dataloader": "^1.4.0",
"redis": "^2.8.0" "redis": "^2.8.0"
},
"devDependencies": {
"@types/redis": "2.8.6",
"redis-mock": "0.29.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -4,7 +4,8 @@ import { promisify } from 'util';
import * as DataLoader from 'dataloader'; import * as DataLoader from 'dataloader';
export class RedisCache implements KeyValueCache { export class RedisCache implements KeyValueCache {
readonly client; // FIXME: Replace any with proper promisified type
readonly client: any;
readonly defaultSetOptions = { readonly defaultSetOptions = {
ttl: 300, ttl: 300,
}; };
@ -12,16 +13,19 @@ export class RedisCache implements KeyValueCache {
private loader: DataLoader<string, string>; private loader: DataLoader<string, string>;
constructor(options: Redis.ClientOpts) { constructor(options: Redis.ClientOpts) {
this.client = Redis.createClient(options); const client = Redis.createClient(options);
// promisify client calls for convenience
client.mget = promisify(client.mget).bind(client);
client.set = promisify(client.set).bind(client);
client.flushdb = promisify(client.flushdb).bind(client);
client.quit = promisify(client.quit).bind(client);
this.client = client;
this.loader = new DataLoader(keys => this.client.mget(keys), { this.loader = new DataLoader(keys => this.client.mget(keys), {
cache: false, cache: false,
}); });
// promisify client calls for convenience
this.client.mget = promisify(this.client.mget).bind(this.client);
this.client.set = promisify(this.client.set).bind(this.client);
this.client.flushdb = promisify(this.client.flushdb).bind(this.client);
this.client.quit = promisify(this.client.quit).bind(this.client);
} }
async set( async set(

View file

@ -2,15 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-caching", "name": "apollo-server-caching",
"version": "0.1.0", "version": "0.1.2",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,7 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"prepublish": "npm run clean && npm run compile" "prepare": "npm run clean && npm run compile"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -23,8 +23,5 @@
}, },
"dependencies": { "dependencies": {
"lru-cache": "^4.1.3" "lru-cache": "^4.1.3"
},
"devDependencies": {
"@types/lru-cache": "4.1.1"
} }
} }

View file

@ -2,16 +2,8 @@
"extends": "../../tsconfig", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"removeComments": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -0,0 +1,6 @@
*
!src/**/*
!dist/**/*
dist/**/*.test.*
!package.json
!README.md

View file

@ -0,0 +1,177 @@
---
title: Google Cloud Functions
description: Setting up Apollo Server with Google Cloud Functions
---
[![npm version](https://badge.fury.io/js/apollo-server-cloud-function.svg)](https://badge.fury.io/js/apollo-server-cloud-function) [![Build Status](https://circleci.com/gh/apollographql/apollo-server.svg?style=svg)](https://circleci.com/gh/apollographql/apollo-server) [![Coverage Status](https://coveralls.io/repos/github/apollographql/apollo-server/badge.svg?branch=master)](https://coveralls.io/github/apollographql/apollo-server?branch=master) [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://www.apollographql.com/#slack)
This is the Google Cloud Function integration of GraphQL Server. Apollo Server is a community-maintained open-source GraphQL server that works with many Node.js HTTP server frameworks. [Read the docs](https://www.apollographql.com/docs/apollo-server/v2). [Read the CHANGELOG](https://github.com/apollographql/apollo-server/blob/master/CHANGELOG.md).
```sh
npm install apollo-server-cloud-function@rc graphql
```
## Deploying with Google Cloud Function
#### 1. Write the API handlers
First, create a `package.json` file and include `apollo-server-cloud-function` in your dependencies. Then in a file named `index.js`, place the following code:
```js
const { ApolloServer, gql } = require('apollo-server-cloud-function');
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
playground: true,
introspection: true,
});
exports.handler = server.createHandler();
```
#### 2. Configure your Cloud Function and deploy
On the Create Function page, set _Trigger_ to `HTTP` and _Function to execute_ to the name of your exported handler, in this case `handler`.
Since NODE_ENV is a reserved environment variable in GCF and it defaults to "production", both the **playground** and **introspection**
options need to be explicitly set to `true` for the GraphQL Playground to work correctly.
After configuring your Function you can press **Create** and an http endpoint will be created a few seconds later.
You can refer to the [Cloud Functions documentation](https://cloud.google.com/functions/docs/quickstart-console) for more details
## Getting request info
To read information about the currently executing Google Cloud Function (HTTP headers, HTTP method, body, path, ...) use the context option. This way you can pass any request specific data to your schema resolvers.
```js
const { ApolloServer, gql } = require('apollo-server-cloud-function');
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => ({
headers: req.headers,
req,
res,
}),
});
exports.handler = server.createHandler();
```
## Modifying the GCF Response (Enable CORS)
To enable CORS the response HTTP headers need to be modified. To accomplish this use the `cors` option.
```js
const { ApolloServer, gql } = require('apollo-server-cloud-function');
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
exports.handler = server.createHandler({
cors: {
origin: '*',
credentials: true,
},
});
```
To enable CORS response for requests with credentials (cookies, http authentication) the allow origin header must equal the request origin and the allow credential header must be set to true.
```js
const { ApolloServer, gql } = require('apollo-server-cloud-function');
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
exports.handler = server.createHandler({
cors: {
origin: true,
credentials: true,
},
});
```
### Cors Options
The options correspond to the [express cors configuration](https://github.com/expressjs/cors#configuration-options) with the following fields(all are optional):
- `origin`: boolean | string | string[]
- `methods`: string | string[]
- `allowedHeaders`: string | string[]
- `exposedHeaders`: string | string[]
- `credentials`: boolean
- `maxAge`: number
## Principles
GraphQL Server is built with the following principles in mind:
- **By the community, for the community**: GraphQL Server's development is driven by the needs of developers
- **Simplicity**: by keeping things simple, GraphQL Server is easier to use, easier to contribute to, and more secure
- **Performance**: GraphQL Server is well-tested and production-ready - no modifications needed
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!

View file

@ -0,0 +1,44 @@
{
"name": "apollo-server-cloud-functions",
"version": "2.0.3",
"description": "Production-ready Node.js GraphQL server for Google Cloud Functions",
"keywords": [
"GraphQL",
"Apollo",
"Server",
"Google Cloud Functions",
"Javascript"
],
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-cloud-functions"
},
"homepage": "https://github.com/apollographql/apollo-server#readme",
"bugs": {
"url": "https://github.com/apollographql/apollo-server/issues"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"engines": {
"node": ">=6"
},
"scripts": {
"clean": "rm -rf dist",
"compile": "tsc",
"prepublish": "npm run clean && npm run compile"
},
"dependencies": {
"@apollographql/graphql-playground-html": "^1.6.0",
"apollo-server-core": "file:../apollo-server-core",
"apollo-server-env": "file:../apollo-server-env",
"graphql-tools": "^3.0.4"
},
"devDependencies": {
"apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
},
"peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
}
}

View file

@ -0,0 +1,139 @@
import { ApolloServerBase, GraphQLOptions, Config } from 'apollo-server-core';
import {
renderPlaygroundPage,
RenderPageOptions as PlaygroundRenderPageOptions,
} from '@apollographql/graphql-playground-html';
import { Request, Response } from 'express';
import { graphqlCloudFunction } from './googleCloudApollo';
export interface CreateHandlerOptions {
cors?: {
origin?: boolean | string | string[];
methods?: string | string[];
allowedHeaders?: string | string[];
exposedHeaders?: string | string[];
credentials?: boolean;
maxAge?: number;
};
}
export class ApolloServer extends ApolloServerBase {
// If you feel tempted to add an option to this constructor. Please consider
// another place, since the documentation becomes much more complicated when
// the constructor is not longer shared between all integration
constructor(options: Config) {
if (process.env.ENGINE_API_KEY || options.engine) {
options.engine = {
sendReportsImmediately: true,
...(typeof options.engine !== 'boolean' ? options.engine : {}),
};
}
super(options);
}
// This translates the arguments from the middleware into graphQL options It
// provides typings for the integration specific behavior, ideally this would
// be propagated with a generic to the super class
createGraphQLServerOptions(
req: Request,
res: Response,
): Promise<GraphQLOptions> {
return super.graphQLServerOptions({ req, res });
}
public createHandler({ cors }: CreateHandlerOptions = { cors: undefined }) {
const corsHeaders = {} as Record<string, any>;
if (cors) {
if (cors.methods) {
if (typeof cors.methods === 'string') {
corsHeaders['Access-Control-Allow-Methods'] = cors.methods;
} else if (Array.isArray(cors.methods)) {
corsHeaders['Access-Control-Allow-Methods'] = cors.methods.join(',');
}
}
if (cors.allowedHeaders) {
if (typeof cors.allowedHeaders === 'string') {
corsHeaders['Access-Control-Allow-Headers'] = cors.allowedHeaders;
} else if (Array.isArray(cors.allowedHeaders)) {
corsHeaders[
'Access-Control-Allow-Headers'
] = cors.allowedHeaders.join(',');
}
}
if (cors.exposedHeaders) {
if (typeof cors.exposedHeaders === 'string') {
corsHeaders['Access-Control-Expose-Headers'] = cors.exposedHeaders;
} else if (Array.isArray(cors.exposedHeaders)) {
corsHeaders[
'Access-Control-Expose-Headers'
] = cors.exposedHeaders.join(',');
}
}
if (cors.credentials) {
corsHeaders['Access-Control-Allow-Credentials'] = 'true';
}
if (cors.maxAge) {
corsHeaders['Access-Control-Max-Age'] = cors.maxAge;
}
}
return (req: Request, res: Response) => {
// Handle both the root of the GCF endpoint and /graphql
if (!['', '/', '/graphql'].includes(req.path)) {
res.status(404).end();
return;
}
if (cors) {
if (typeof cors.origin === 'string') {
res.set('Access-Control-Allow-Origin', cors.origin);
} else if (
typeof cors.origin === 'boolean' ||
(Array.isArray(cors.origin) &&
cors.origin.includes(req.get('origin') || ''))
) {
res.set('Access-Control-Allow-Origin', req.get('origin'));
}
if (!cors.allowedHeaders) {
res.set(
'Access-Control-Allow-Headers',
req.get('Access-Control-Request-Headers'),
);
}
}
if (req.method === 'OPTIONS') {
res.status(204).send('');
return;
}
if (this.playgroundOptions && req.method === 'GET') {
const acceptHeader = req.headers['accept'] as string;
if (acceptHeader && acceptHeader.includes('text/html')) {
const playgroundRenderPageOptions: PlaygroundRenderPageOptions = {
endpoint: req.get('referer'),
...this.playgroundOptions,
};
res
.status(200)
.send(renderPlaygroundPage(playgroundRenderPageOptions));
return;
}
}
res.set(corsHeaders);
graphqlCloudFunction(this.createGraphQLServerOptions.bind(this))(
req,
res,
);
};
}
}

View file

@ -0,0 +1,25 @@
import { ApolloServer } from '../ApolloServer';
import testSuite, {
schema as Schema,
CreateAppOptions,
} from 'apollo-server-integration-testsuite';
import { Config } from 'apollo-server-core';
import express = require('express');
import bodyParser = require('body-parser');
const createCloudFunction = (options: CreateAppOptions = {}) => {
const handler = new ApolloServer(
(options.graphqlOptions as Config) || { schema: Schema },
).createHandler();
// We use Express to simulate the Google Cloud
// Function like environment
const app = express();
app.use(bodyParser.json());
app.use(handler);
return app;
};
describe('integration:CloudFunction', () => {
testSuite(createCloudFunction);
});

View file

@ -0,0 +1,57 @@
import {
GraphQLOptions,
HttpQueryError,
runHttpQuery,
} from 'apollo-server-core';
import { Headers } from 'apollo-server-env';
import { Request, Response } from 'express';
export function graphqlCloudFunction(options: GraphQLOptions): any {
if (!options) {
throw new Error('Apollo Server requires options.');
}
if (arguments.length > 1) {
throw new Error(
`Apollo Server expects exactly one argument, got ${arguments.length}`,
);
}
const graphqlHandler: any = (req: Request, res: Response): void => {
const hasPostBody = req.body && Object.keys(req.body).length > 0;
if (req.method === 'POST' && !hasPostBody) {
res.status(500).send('POST body missing.');
return;
}
runHttpQuery([req, res], {
method: req.method,
options: options,
query: hasPostBody ? req.body : (req.query as any),
request: {
url: req.url,
method: req.method,
headers: new Headers(req.headers as any), // ? Check if this actually works
},
}).then(
({ graphqlResponse, responseInit }) => {
res
.status(200)
.set(responseInit.headers)
.send(graphqlResponse);
},
(error: HttpQueryError) => {
if ('HttpQueryError' !== error.name) {
res.status(500).send(error);
return;
}
res
.status(error.statusCode)
.set(error.headers)
.send(error.message);
},
);
};
return graphqlHandler;
}

View file

@ -0,0 +1,24 @@
export {
GraphQLUpload,
GraphQLOptions,
GraphQLExtension,
Config,
gql,
// Errors
ApolloError,
toApolloError,
SyntaxError,
ValidationError,
AuthenticationError,
ForbiddenError,
UserInputError,
// playground
defaultPlaygroundOptions,
PlaygroundConfig,
PlaygroundRenderPageOptions,
} from 'apollo-server-core';
export * from 'graphql-tools';
// ApolloServer integration.
export { ApolloServer, CreateHandlerOptions } from './ApolloServer';

View file

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["**/__tests__", "**/__mocks__"]
}

View file

@ -1,15 +1,13 @@
{ {
"name": "apollo-server-cloudflare", "name": "apollo-server-cloudflare",
"version": "2.0.0-rc.12", "version": "2.0.4",
"description": "Production-ready Node.js GraphQL server for Cloudflare workers", "description": "Production-ready Node.js GraphQL server for Cloudflare workers",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -28,35 +26,10 @@
}, },
"homepage": "https://github.com/apollographql/apollo-server#readme", "homepage": "https://github.com/apollographql/apollo-server#readme",
"dependencies": { "dependencies": {
"apollo-server-core": "2.0.0", "apollo-server-core": "file:../apollo-server-core",
"apollo-server-env": "2.0.0" "apollo-server-env": "file:../apollo-server-env"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -47,15 +47,9 @@ export function graphqlCloudflare(options: GraphQLOptions) {
const res = new Response(error.message, { const res = new Response(error.message, {
status: error.statusCode, status: error.statusCode,
headers: { 'content-type': 'application/json' }, headers: error.headers,
}); });
if (error.headers) {
Object.keys(error.headers).forEach(header => {
res.headers[header] = error.headers[header];
});
}
return res; return res;
}, },
); );

View file

@ -1,7 +1,3 @@
export * from 'graphql-tools';
export { ApolloServer } from './ApolloServer';
export { export {
GraphQLUpload, GraphQLUpload,
GraphQLOptions, GraphQLOptions,
@ -21,3 +17,7 @@ export {
PlaygroundConfig, PlaygroundConfig,
PlaygroundRenderPageOptions, PlaygroundRenderPageOptions,
} from 'apollo-server-core'; } from 'apollo-server-core';
export { ApolloServer } from './ApolloServer';
export * from 'graphql-tools';

View file

@ -1,9 +1,9 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist" "outDir": "./dist"
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -5,11 +5,9 @@
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -31,16 +29,16 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"@apollographql/apollo-upload-server": "^5.0.3",
"@types/ws": "^5.1.2", "@types/ws": "^5.1.2",
"apollo-cache-control": "0.2.0", "apollo-cache-control": "file:../apollo-cache-control",
"apollo-datasource": "0.1.0", "apollo-datasource": "file:../apollo-datasource",
"apollo-engine-reporting": "0.0.0", "apollo-engine-reporting": "file:../apollo-engine-reporting",
"apollo-server-caching": "0.1.0", "apollo-server-caching": "file:../apollo-server-caching",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"apollo-server-errors": "2.0.0", "apollo-server-errors": "file:../apollo-server-errors",
"apollo-tracing": "0.2.0", "apollo-tracing": "file:../apollo-tracing",
"apollo-upload-server": "^5.0.0", "graphql-extensions": "file:../graphql-extensions",
"graphql-extensions": "0.1.0",
"graphql-subscriptions": "^0.5.8", "graphql-subscriptions": "^0.5.8",
"graphql-tag": "^2.9.2", "graphql-tag": "^2.9.2",
"graphql-tools": "^3.0.4", "graphql-tools": "^3.0.4",
@ -52,44 +50,5 @@
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"devDependencies": {
"@types/fibers": "0.0.30",
"@types/graphql": "0.13.3",
"@types/keyv": "3.0.1",
"@types/quick-lru": "1.1.0",
"apollo-fetch": "0.7.0",
"apollo-link": "1.2.2",
"apollo-link-http": "1.5.4",
"apollo-link-persisted-queries": "0.2.1",
"fibers": "2.0.2",
"js-sha256": "0.9.0",
"meteor-promise": "0.8.6",
"mock-req": "0.2.0"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/node_modules/apollo-server-env/dist/index.js"
],
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*.(spec|test).(js|ts)?$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -15,8 +15,6 @@ import { GraphQLExtension } from 'graphql-extensions';
import { EngineReportingAgent } from 'apollo-engine-reporting'; import { EngineReportingAgent } from 'apollo-engine-reporting';
import { InMemoryLRUCache } from 'apollo-server-caching'; import { InMemoryLRUCache } from 'apollo-server-caching';
import { GraphQLUpload } from 'apollo-upload-server';
import { import {
SubscriptionServer, SubscriptionServer,
ExecutionParams, ExecutionParams,
@ -64,10 +62,11 @@ export class ApolloServerBase {
public graphqlPath: string = '/graphql'; public graphqlPath: string = '/graphql';
public requestOptions: Partial<GraphQLOptions<any>>; public requestOptions: Partial<GraphQLOptions<any>>;
private schema: GraphQLSchema;
private context?: Context | ContextFunction; private context?: Context | ContextFunction;
private engineReportingAgent?: EngineReportingAgent; private engineReportingAgent?: EngineReportingAgent;
private extensions: Array<() => GraphQLExtension>; private extensions: Array<() => GraphQLExtension>;
protected schema: GraphQLSchema;
protected subscriptionServerOptions?: SubscriptionServerOptions; protected subscriptionServerOptions?: SubscriptionServerOptions;
protected uploadsConfig?: FileUploadOptions; protected uploadsConfig?: FileUploadOptions;
@ -88,6 +87,7 @@ export class ApolloServerBase {
typeDefs, typeDefs,
introspection, introspection,
mocks, mocks,
mockEntireSchema,
extensions, extensions,
engine, engine,
subscriptions, subscriptions,
@ -150,13 +150,6 @@ export class ApolloServerBase {
} }
} }
//Add upload resolver
if (this.uploadsConfig) {
if (resolvers && !resolvers.Upload) {
resolvers.Upload = GraphQLUpload;
}
}
if (schema) { if (schema) {
// @defer directive should be added by default // @defer directive should be added by default
const newDirectives = schema.getDirectives().slice(); const newDirectives = schema.getDirectives().slice();
@ -177,28 +170,64 @@ export class ApolloServerBase {
); );
} }
const deferDirectiveDef = gql` let augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
directive @defer(if: Boolean = true) on FIELD
`; // Add support for @defer directive.
const uploadScalarDef = gql` augmentedTypeDefs.push(
scalar Upload gql`
`; directive @defer(if: Boolean = true) on FIELD
`,
);
// We augment the typeDefs with the @cacheControl directive and associated
// scope enum, so makeExecutableSchema won't fail SDL validation
augmentedTypeDefs.push(
gql`
enum CacheControlScope {
PUBLIC
PRIVATE
}
directive @cacheControl(
maxAge: Int
scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE
`,
);
if (this.uploadsConfig) {
const {
GraphQLUpload,
} = require('@apollographql/apollo-upload-server');
if (resolvers && !resolvers.Upload) {
resolvers.Upload = GraphQLUpload;
}
// We augment the typeDefs with the Upload scalar, so typeDefs that
// don't include it won't fail
augmentedTypeDefs.push(
gql`
scalar Upload
`,
);
}
this.schema = makeExecutableSchema({ this.schema = makeExecutableSchema({
// Add in the upload scalar, and @defer directive so that schemas typeDefs: augmentedTypeDefs,
// that don't include it won't error when we makeExecutableSchema
typeDefs: this.uploadsConfig
? [uploadScalarDef, deferDirectiveDef].concat(typeDefs)
: [deferDirectiveDef].concat(typeDefs),
schemaDirectives, schemaDirectives,
resolvers, resolvers,
}); });
} }
if (mocks) { if (mocks || typeof mockEntireSchema !== 'undefined') {
addMockFunctionsToSchema({ addMockFunctionsToSchema({
schema: this.schema, schema: this.schema,
preserveResolvers: true, mocks:
mocks: typeof mocks === 'boolean' ? {} : mocks, typeof mocks === 'boolean' || typeof mocks === 'undefined'
? {}
: mocks,
preserveResolvers:
typeof mockEntireSchema === 'undefined' ? false : !mockEntireSchema,
}); });
} }
@ -302,7 +331,10 @@ export class ApolloServerBase {
? onConnect ? onConnect
: (connectionParams: Object) => ({ ...connectionParams }), : (connectionParams: Object) => ({ ...connectionParams }),
onDisconnect: onDisconnect, onDisconnect: onDisconnect,
onOperation: async (_: string, connection: ExecutionParams) => { onOperation: async (
message: { payload: any },
connection: ExecutionParams,
) => {
connection.formatResponse = (value: ExecutionResult) => ({ connection.formatResponse = (value: ExecutionResult) => ({
...value, ...value,
errors: errors:
@ -317,7 +349,7 @@ export class ApolloServerBase {
try { try {
context = context =
typeof this.context === 'function' typeof this.context === 'function'
? await this.context({ connection }) ? await this.context({ connection, payload: message.payload })
: context; : context;
} catch (e) { } catch (e) {
throw formatApolloErrors([e], { throw formatApolloErrors([e], {

View file

@ -449,6 +449,28 @@ describe('runQuery', () => {
}); });
}); });
}); });
it('runs willSendResponse with extensions context', async () => {
class CustomExtension implements GraphQLExtension<any> {
willSendResponse(o: any) {
expect(o).toHaveProperty('context.baz', 'always here');
return o;
}
}
const queryString = `{ testString }`;
const expected = { testString: 'it works' };
const extensions = [() => new CustomExtension()];
return runQuery({
schema,
queryString,
context: { baz: 'always here' },
extensions,
request: new MockReq(),
}).then(res => {
expect(res.data).toEqual(expected);
});
});
}); });
describe('async_hooks', () => { describe('async_hooks', () => {

View file

@ -1,7 +1,7 @@
import { GraphQLExtension, GraphQLResponse } from 'graphql-extensions'; import { GraphQLExtension, GraphQLResponse } from 'graphql-extensions';
import { formatApolloErrors } from 'apollo-server-errors'; import { formatApolloErrors } from 'apollo-server-errors';
export class FormatErrorExtension extends GraphQLExtension { export class FormatErrorExtension<TContext = any> extends GraphQLExtension {
private formatError: Function; private formatError: Function;
private debug: boolean; private debug: boolean;
@ -13,9 +13,11 @@ export class FormatErrorExtension extends GraphQLExtension {
public willSendResponse(o: { public willSendResponse(o: {
graphqlResponse: GraphQLResponse; graphqlResponse: GraphQLResponse;
}): void | { graphqlResponse: GraphQLResponse } { context: TContext;
}): void | { graphqlResponse: GraphQLResponse; context: TContext } {
if (o.graphqlResponse.errors) { if (o.graphqlResponse.errors) {
return { return {
...o,
graphqlResponse: { graphqlResponse: {
...o.graphqlResponse, ...o.graphqlResponse,
errors: formatApolloErrors(o.graphqlResponse.errors, { errors: formatApolloErrors(o.graphqlResponse.errors, {

View file

@ -44,5 +44,5 @@ export const gql: (
) => DocumentNode = gqlTag; ) => DocumentNode = gqlTag;
import { GraphQLScalarType } from 'graphql'; import { GraphQLScalarType } from 'graphql';
import { GraphQLUpload as UploadScalar } from 'apollo-upload-server'; import { GraphQLUpload as UploadScalar } from '@apollographql/apollo-upload-server';
export const GraphQLUpload = UploadScalar as GraphQLScalarType; export const GraphQLUpload = UploadScalar as GraphQLScalarType;

View file

@ -9,7 +9,7 @@ export {
// This specifies the version of GraphQL Playground that will be served // This specifies the version of GraphQL Playground that will be served
// from graphql-playground-html, and is passed to renderPlaygroundPage // from graphql-playground-html, and is passed to renderPlaygroundPage
// by the integration subclasses // by the integration subclasses
const playgroundVersion = '1.7.2'; const playgroundVersion = '1.7.4';
// https://stackoverflow.com/a/51365037 // https://stackoverflow.com/a/51365037
type RecursivePartial<T> = { type RecursivePartial<T> = {
@ -39,7 +39,8 @@ export function createPlaygroundOptions(
playground: PlaygroundConfig = {}, playground: PlaygroundConfig = {},
): PlaygroundRenderPageOptions | undefined { ): PlaygroundRenderPageOptions | undefined {
const isDev = process.env.NODE_ENV !== 'production'; const isDev = process.env.NODE_ENV !== 'production';
const enabled: boolean = typeof playground === 'boolean' ? playground : isDev; const enabled: boolean =
typeof playground !== 'undefined' ? !!playground : isDev;
if (!enabled) { if (!enabled) {
return undefined; return undefined;
@ -48,14 +49,20 @@ export function createPlaygroundOptions(
const playgroundOverrides = const playgroundOverrides =
typeof playground === 'boolean' ? {} : playground || {}; typeof playground === 'boolean' ? {} : playground || {};
const settingsOverrides = playgroundOverrides.hasOwnProperty('settings')
? {
settings: {
...defaultPlaygroundOptions.settings,
...playgroundOverrides.settings,
},
}
: { settings: undefined };
const playgroundOptions: PlaygroundRenderPageOptions = { const playgroundOptions: PlaygroundRenderPageOptions = {
...defaultPlaygroundOptions, ...defaultPlaygroundOptions,
...playgroundOverrides, ...playgroundOverrides,
settings: { ...settingsOverrides,
...defaultPlaygroundOptions.settings, };
...playgroundOverrides.settings,
},
} as PlaygroundRenderPageOptions; // TODO: Remove casting when strict mode = true in apollo-server-core tsconfig
return playgroundOptions; return playgroundOptions;
} }

View file

@ -161,6 +161,7 @@ function doRunQuery(
variables: options.variables, variables: options.variables,
persistedQueryHit: options.persistedQueryHit, persistedQueryHit: options.persistedQueryHit,
persistedQueryRegister: options.persistedQueryRegister, persistedQueryRegister: options.persistedQueryRegister,
context,
}); });
return Promise.resolve() return Promise.resolve()
.then( .then(
@ -332,7 +333,8 @@ function doRunQuery(
// the patches have been resolved. // the patches have been resolved.
if (isDeferredGraphQLResponse(graphqlResponse)) { if (isDeferredGraphQLResponse(graphqlResponse)) {
const response = extensionStack.willSendResponse({ const response = extensionStack.willSendResponse({
graphqlResponse: graphqlResponse.initialResponse, graphqlResponse: graphqlResponse.initialResponse as GraphQLResponse,
context,
}); });
return { return {
...graphqlResponse, ...graphqlResponse,
@ -341,6 +343,7 @@ function doRunQuery(
} else { } else {
const response = extensionStack.willSendResponse({ const response = extensionStack.willSendResponse({
graphqlResponse: graphqlResponse as GraphQLResponse, graphqlResponse: graphqlResponse as GraphQLResponse,
context,
}); });
requestDidEnd(); requestDidEnd();
return response.graphqlResponse; return response.graphqlResponse;

View file

@ -56,6 +56,7 @@ export interface Config
context?: Context<any> | ContextFunction<any>; context?: Context<any> | ContextFunction<any>;
introspection?: boolean; introspection?: boolean;
mocks?: boolean | IMocks; mocks?: boolean | IMocks;
mockEntireSchema?: boolean;
engine?: boolean | EngineReportingOptions; engine?: boolean | EngineReportingOptions;
extensions?: Array<() => GraphQLExtension>; extensions?: Array<() => GraphQLExtension>;
persistedQueries?: PersistedQueryOptions | false; persistedQueries?: PersistedQueryOptions | false;

View file

@ -1,5 +1,27 @@
declare module 'apollo-upload-server' { declare module '@apollographql/apollo-upload-server' {
import { GraphQLScalarType } from 'graphql'; import { GraphQLScalarType } from 'graphql';
export const GraphQLUpload: GraphQLScalarType; export const GraphQLUpload: GraphQLScalarType;
export interface ApolloUploadOptions {
/**
* Max allowed non-file multipart form field size in bytes; enough for your queries (default: 1 MB)
*/
maxFieldSize?: number;
/**
* Max allowed file size in bytes (default: Infinity)
*/
maxFileSize?: number;
/**
* Max allowed number of files (default: Infinity)
*/
maxFiles?: number;
}
export type Request = any;
export function processRequest(
request: Request,
options?: ApolloUploadOptions,
): Promise<any>;
} }

View file

@ -1,15 +1,9 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"strict": true,
"noImplicitAny": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-env", "name": "apollo-server-env",
"version": "2.0.0", "version": "2.0.3",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,9 +14,10 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc && cp src/*.d.ts dist", "compile": "tsc && cp src/*.d.ts dist",
"prepublish": "npm run clean && npm run compile" "prepare": "npm run clean && npm run compile"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"browser": "dist/index.browser.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"engines": { "engines": {
"node": ">=6" "node": ">=6"

View file

@ -1,3 +1,5 @@
import { Agent } from 'http';
export declare function fetch( export declare function fetch(
input?: RequestInfo, input?: RequestInfo,
init?: RequestInit, init?: RequestInit,
@ -50,6 +52,14 @@ export interface RequestInit {
referrer?: string; referrer?: string;
referrerPolicy?: ReferrerPolicy; referrerPolicy?: ReferrerPolicy;
integrity?: string; integrity?: string;
// The following properties are node-fetch extensions
follow?: number;
timeout?: number;
compress?: boolean;
size?: number;
agent?: Agent;
// Cloudflare Workers accept a `cf` property to control Cloudflare features // Cloudflare Workers accept a `cf` property to control Cloudflare features
// See https://developers.cloudflare.com/workers/reference/cloudflare-features/ // See https://developers.cloudflare.com/workers/reference/cloudflare-features/
cf?: { cf?: {

View file

@ -0,0 +1,45 @@
if (!global) {
global = self;
}
let { fetch, Request, Response, Headers, URL, URLSearchParams } = global;
fetch = fetch.bind(global);
export { fetch, Request, Response, Headers, URL, URLSearchParams };
if (!global.process) {
global.process = {};
}
if (!global.process.env) {
global.process.env = {
// app is a global available on fly.io
NODE_ENV: app ? app.env : 'production',
};
}
if (!global.process.version) {
global.process.version = '';
}
if (!global.process.hrtime) {
// Adapted from https://github.com/kumavis/browser-process-hrtime
global.process.hrtime = function hrtime(previousTimestamp) {
var clocktime = Date.now() * 1e-3;
var seconds = Math.floor(clocktime);
var nanoseconds = Math.floor((clocktime % 1) * 1e9);
if (previousTimestamp) {
seconds = seconds - previousTimestamp[0];
nanoseconds = nanoseconds - previousTimestamp[1];
if (nanoseconds < 0) {
seconds--;
nanoseconds += 1e9;
}
}
return [seconds, nanoseconds];
};
}
if (!global.os) {
// FIXME: Add some sensible values
global.os = {};
}

View file

@ -1,4 +1,5 @@
import './polyfills/Object.values'; import './polyfills/Object.values';
import './polyfills/Object.entries';
require('util.promisify').shim(); require('util.promisify').shim();

View file

@ -0,0 +1,5 @@
if (!global.Object.entries) {
global.Object.entries = function(object: any) {
return Object.keys(object).map(key => [key, object[key]] as [string, any]);
};
}

View file

@ -1,13 +1,5 @@
interface ObjectConstructor {
/**
* Returns an array of values of the enumerable properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
values<T>(o: { [s: string]: T } | ArrayLike<T>): T[];
}
if (!global.Object.values) { if (!global.Object.values) {
global.Object.values = function(o) { global.Object.values = function(object: any) {
return Object.keys(o).map(key => o[key]); return Object.keys(object).map(key => object[key]);
}; };
} }

View file

@ -5,15 +5,8 @@
"outDir": "./dist", "outDir": "./dist",
"allowJs": true, "allowJs": true,
"declaration": false, "declaration": false,
"declarationMap": false, "declarationMap": false
"removeComments": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"], "exclude": ["**/__tests__", "**/__mocks__"]
"types": []
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-errors", "name": "apollo-server-errors",
"version": "2.0.0", "version": "2.0.2",
"author": "opensource@apollographql.com", "author": "opensource@apollographql.com",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -14,7 +14,7 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"prepublish": "npm run clean && npm run compile" "prepare": "npm run clean && npm run compile"
}, },
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View file

@ -3,14 +3,8 @@
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"removeComments": true, "noImplicitAny": false
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -5,11 +5,9 @@
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -33,14 +31,14 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"@apollographql/apollo-upload-server": "^5.0.3",
"@apollographql/graphql-playground-html": "^1.6.0", "@apollographql/graphql-playground-html": "^1.6.0",
"@types/accepts": "^1.3.5", "@types/accepts": "^1.3.5",
"@types/body-parser": "1.17.0", "@types/body-parser": "1.17.0",
"@types/cors": "^2.8.4", "@types/cors": "^2.8.4",
"@types/express": "4.16.0", "@types/express": "4.16.0",
"accepts": "^1.3.5", "accepts": "^1.3.5",
"apollo-server-core": "2.1.0-alpha.10", "apollo-server-core": "file:../apollo-server-core",
"apollo-upload-server": "^5.0.0",
"body-parser": "^1.18.3", "body-parser": "^1.18.3",
"cors": "^2.8.4", "cors": "^2.8.4",
"graphql-subscriptions": "^0.5.8", "graphql-subscriptions": "^0.5.8",
@ -49,40 +47,9 @@
"type-is": "^1.6.16" "type-is": "^1.6.16"
}, },
"devDependencies": { "devDependencies": {
"@types/connect": "3.4.32", "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
"@types/multer": "1.3.7",
"apollo-datasource-rest": "0.1.0",
"apollo-server-integration-testsuite": "2.0.0",
"connect": "3.6.6",
"express": "4.16.3",
"form-data": "2.3.2",
"multer": "1.3.1",
"node-fetch": "2.2.0",
"qs-middleware": "1.0.3"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"jest": {
"testEnvironment": "node",
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -16,7 +16,7 @@ import * as typeis from 'type-is';
import { graphqlExpress } from './expressApollo'; import { graphqlExpress } from './expressApollo';
import { processRequest as processFileUploads } from 'apollo-upload-server'; import { processRequest as processFileUploads } from '@apollographql/apollo-upload-server';
export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core'; export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core';

View file

@ -171,6 +171,7 @@ describe('apollo-server-express', () => {
reject(error); reject(error);
} else { } else {
expect(body).toMatch('GraphQLPlayground'); expect(body).toMatch('GraphQLPlayground');
expect(body).not.toMatch('settings');
expect(response.statusCode).toEqual(200); expect(response.statusCode).toEqual(200);
resolve(); resolve();
} }
@ -179,10 +180,7 @@ describe('apollo-server-express', () => {
}); });
}); });
it('accepts partial GraphQL Playground Options', async () => { const playgroundPartialOptionsTest = async () => {
const nodeEnv = process.env.NODE_ENV;
delete process.env.NODE_ENV;
const defaultQuery = 'query { foo { bar } }'; const defaultQuery = 'query { foo { bar } }';
const endpoint = '/fumanchupacabra'; const endpoint = '/fumanchupacabra';
const { url } = await createServer( const { url } = await createServer(
@ -220,7 +218,6 @@ describe('apollo-server-express', () => {
}, },
}, },
(error, response, body) => { (error, response, body) => {
process.env.NODE_ENV = nodeEnv;
if (error) { if (error) {
reject(error); reject(error);
} else { } else {
@ -234,8 +231,26 @@ describe('apollo-server-express', () => {
}, },
); );
}); });
};
it('accepts partial GraphQL Playground Options in production', async () => {
const nodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'production';
await playgroundPartialOptionsTest();
process.env.NODE_ENV = nodeEnv;
}); });
it(
'accepts partial GraphQL Playground Options when an environment is ' +
'not specified',
async () => {
const nodeEnv = process.env.NODE_ENV;
delete process.env.NODE_ENV;
await playgroundPartialOptionsTest();
process.env.NODE_ENV = nodeEnv;
},
);
it('accepts playground options as a boolean', async () => { it('accepts playground options as a boolean', async () => {
const nodeEnv = process.env.NODE_ENV; const nodeEnv = process.env.NODE_ENV;
delete process.env.NODE_ENV; delete process.env.NODE_ENV;

View file

@ -1,10 +1,11 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"lib": ["es2017", "esnext.asynciterable", "dom"] "noImplicitAny": false,
"strictNullChecks": false
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -5,11 +5,9 @@
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -32,43 +30,19 @@
"node": ">=8" "node": ">=8"
}, },
"dependencies": { "dependencies": {
"@apollographql/apollo-upload-server": "^5.0.3",
"@apollographql/graphql-playground-html": "^1.6.0", "@apollographql/graphql-playground-html": "^1.6.0",
"accept": "^3.0.2", "accept": "^3.0.2",
"apollo-server-core": "2.1.0-alpha.10", "apollo-server-core": "file:../apollo-server-core",
"apollo-upload-server": "^5.0.0",
"boom": "^7.1.0", "boom": "^7.1.0",
"graphql-subscriptions": "^0.5.8", "graphql-subscriptions": "^0.5.8",
"graphql-tools": "^3.0.4", "graphql-tools": "^3.0.4",
"iterall": "^1.2.2" "iterall": "^1.2.2"
}, },
"devDependencies": { "devDependencies": {
"@types/hapi": "17.0.17", "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
"apollo-server-integration-testsuite": "2.0.0",
"hapi": "17.5.3"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"jest": {
"testEnvironment": "node",
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -4,7 +4,7 @@ import {
renderPlaygroundPage, renderPlaygroundPage,
RenderPageOptions as PlaygroundRenderPageOptions, RenderPageOptions as PlaygroundRenderPageOptions,
} from '@apollographql/graphql-playground-html'; } from '@apollographql/graphql-playground-html';
import { processRequest as processFileUploads } from 'apollo-upload-server'; import { processRequest as processFileUploads } from '@apollographql/apollo-upload-server';
import { graphqlHapi } from './hapiApollo'; import { graphqlHapi } from './hapiApollo';
@ -49,6 +49,7 @@ export class ApolloServer extends ApolloServerBase {
app, app,
cors, cors,
path, path,
route,
disableHealthCheck, disableHealthCheck,
onHealthCheck, onHealthCheck,
}: ServerRegistration) { }: ServerRegistration) {
@ -122,9 +123,12 @@ export class ApolloServer extends ApolloServerBase {
options: { options: {
path, path,
graphqlOptions: this.createGraphQLServerOptions.bind(this), graphqlOptions: this.createGraphQLServerOptions.bind(this),
route: { route:
cors: cors !== undefined ? cors : true, route !== undefined
}, ? route
: {
cors: cors !== undefined ? cors : true,
},
}, },
}); });
@ -136,6 +140,7 @@ export interface ServerRegistration {
app?: hapi.Server; app?: hapi.Server;
path?: string; path?: string;
cors?: boolean | hapi.RouteOptionsCors; cors?: boolean | hapi.RouteOptionsCors;
route?: hapi.RouteOptions;
onHealthCheck?: (request: hapi.Request) => Promise<any>; onHealthCheck?: (request: hapi.Request) => Promise<any>;
disableHealthCheck?: boolean; disableHealthCheck?: boolean;
uploads?: boolean | Record<string, any>; uploads?: boolean | Record<string, any>;

View file

@ -232,6 +232,50 @@ describe('apollo-server-hapi', () => {
await apolloFetch({ query: '{hello}' }); await apolloFetch({ query: '{hello}' });
}); });
it('accepts custom route configuration', async () => {
server = new ApolloServer({
typeDefs,
resolvers,
});
app = new Server({
port,
});
await server.applyMiddleware({
app,
route: {
cors: {
additionalExposedHeaders: ['X-Apollo'],
exposedHeaders: [
'Accept',
'Authorization',
'Content-Type',
'If-None-Match',
'Another-One',
],
},
},
});
await app.start();
httpServer = app.listener;
const uri = app.info.uri + '/graphql';
const apolloFetch = createApolloFetch({ uri }).useAfter(
(response, next) => {
expect(
response.response.headers.get('access-control-expose-headers'),
).toEqual(
'Accept,Authorization,Content-Type,If-None-Match,Another-One,X-Apollo',
);
next();
},
);
await apolloFetch({ query: '{hello}' });
});
it('passes each request and response toolkit through to the context function', async () => { it('passes each request and response toolkit through to the context function', async () => {
const context = async ({ request, h }) => { const context = async ({ request, h }) => {
expect(request).toBeDefined(); expect(request).toBeDefined();

View file

@ -1,10 +1,12 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"lib": ["es2017", "esnext.asynciterable", "dom"] "noImplicitAny": false,
"noImplicitThis": false,
"strictNullChecks": false
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,14 +1,14 @@
{ {
"name": "apollo-server-integration-testsuite", "name": "apollo-server-integration-testsuite",
"private": true, "private": true,
"version": "2.0.0", "version": "2.0.6",
"description": "Apollo Server Integrations testsuite", "description": "Apollo Server Integrations testsuite",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"prepublish": "npm run compile", "prepare": "npm run clean && npm run compile"
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -25,23 +25,6 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"apollo-server-core": "2.0.0" "apollo-server-core": "file:../apollo-server-core"
},
"devDependencies": {
"@types/body-parser": "1.17.0",
"apollo-engine-reporting-protobuf": "0.0.0-beta.7",
"apollo-fetch": "0.7.0",
"apollo-link": "1.2.2",
"apollo-link-http": "1.5.4",
"apollo-link-persisted-queries": "0.2.1",
"apollo-server-env": "2.0.0",
"body-parser": "1.18.3",
"graphql-extensions": "0.1.0",
"graphql-subscriptions": "0.5.8",
"graphql-tag": "2.9.2",
"js-sha256": "0.9.0",
"subscriptions-transport-ws": "0.9.14",
"ws": "5.2.2",
"yup": "0.26.0"
} }
} }

View file

@ -271,6 +271,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
expect(result.data).toEqual({ testString: 'test string' }); expect(result.data).toEqual({ testString: 'test string' });
expect(result.errors).toBeUndefined(); expect(result.errors).toBeUndefined();
}); });
it('allows mocks as boolean', async () => { it('allows mocks as boolean', async () => {
const typeDefs = gql` const typeDefs = gql`
type Query { type Query {
@ -305,6 +306,84 @@ export function testApolloServer<AS extends ApolloServerBase>(
expect(result.data).toEqual({ hello: 'mock city' }); expect(result.data).toEqual({ hello: 'mock city' });
expect(result.errors).toBeUndefined(); expect(result.errors).toBeUndefined();
}); });
it('allows mocks as an object without overriding the existing resolvers', async () => {
const typeDefs = gql`
type User {
first: String
last: String
}
type Query {
user: User
}
`;
const resolvers = {
Query: {
user: () => ({
first: 'James',
last: 'Heinlen',
}),
},
};
const { url: uri } = await createApolloServer({
typeDefs,
resolvers,
mocks: {
User: () => ({
last: () => 'mock city',
}),
},
});
const apolloFetch = createApolloFetch({ uri });
const result = await apolloFetch({
query: '{user{first last}}',
});
expect(result.data).toEqual({
user: { first: 'Hello World', last: 'mock city' },
});
expect(result.errors).toBeUndefined();
});
// Need to fix bug in graphql-tools to enable mocks to override the existing resolvers
it.skip('allows mocks as an object with overriding the existing resolvers', async () => {
const typeDefs = gql`
type User {
first: String
last: String
}
type Query {
user: User
}
`;
const resolvers = {
Query: {
user: () => ({
first: 'James',
last: 'Heinlen',
}),
},
};
const { url: uri } = await createApolloServer({
typeDefs,
resolvers,
mocks: {
User: () => ({
last: () => 'mock city',
}),
},
mockEntireSchema: false,
});
const apolloFetch = createApolloFetch({ uri });
const result = await apolloFetch({
query: '{user{first last}}',
});
expect(result.data).toEqual({
user: { first: 'James', last: 'mock city' },
});
expect(result.errors).toBeUndefined();
});
}); });
}); });
@ -447,8 +526,11 @@ export function testApolloServer<AS extends ApolloServerBase>(
return error; return error;
}); });
class Extension extends GraphQLExtension { class Extension<TContext = any> extends GraphQLExtension {
willSendResponse(o: { graphqlResponse: GraphQLResponse }) { willSendResponse(o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}) {
expect(o.graphqlResponse.errors.length).toEqual(1); expect(o.graphqlResponse.errors.length).toEqual(1);
// formatError should be called after extensions // formatError should be called after extensions
expect(formatError).not.toBeCalled(); expect(formatError).not.toBeCalled();
@ -530,8 +612,11 @@ export function testApolloServer<AS extends ApolloServerBase>(
return error; return error;
}); });
class Extension extends GraphQLExtension { class Extension<TContext = any> extends GraphQLExtension {
willSendResponse(_o: { graphqlResponse: GraphQLResponse }) { willSendResponse(_o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}) {
// formatError should be called after extensions // formatError should be called after extensions
expect(formatError).not.toBeCalled(); expect(formatError).not.toBeCalled();
extension(); extension();

View file

@ -442,7 +442,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
}, },
}); });
return req.then(res => { return req.then(res => {
expect(res.status).toEqual(200); expect(res.statusCode).toEqual(200);
expect(res.body.errors).toBeDefined(); expect(res.body.errors).toBeDefined();
expect(res.body.errors.length).toEqual(1); expect(res.body.errors.length).toEqual(1);
expect(res.body.errors[0].message).toEqual( expect(res.body.errors[0].message).toEqual(
@ -465,7 +465,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
}), }),
}); });
return req.then(res => { return req.then(res => {
expect(res.status).toEqual(200); expect(res.statusCode).toEqual(200);
expect(res.body.errors).toBeDefined(); expect(res.body.errors).toBeDefined();
expect(res.body.errors.length).toEqual(1); expect(res.body.errors.length).toEqual(1);
expect(res.body.errors[0].message).toEqual('PersistedQueryNotFound'); expect(res.body.errors[0].message).toEqual('PersistedQueryNotFound');

View file

@ -1,10 +1,12 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"noImplicitAny": false,
"strictNullChecks": false,
"lib": ["es2017", "esnext.asynciterable", "dom"] "lib": ["es2017", "esnext.asynciterable", "dom"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -5,11 +5,9 @@
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -32,6 +30,7 @@
"node": ">=6" "node": ">=6"
}, },
"dependencies": { "dependencies": {
"@apollographql/apollo-upload-server": "^5.0.3",
"@apollographql/graphql-playground-html": "^1.6.0", "@apollographql/graphql-playground-html": "^1.6.0",
"@koa/cors": "^2.2.1", "@koa/cors": "^2.2.1",
"@types/accepts": "^1.3.5", "@types/accepts": "^1.3.5",
@ -41,8 +40,7 @@
"@types/koa-compose": "^3.2.2", "@types/koa-compose": "^3.2.2",
"@types/koa__cors": "^2.2.1", "@types/koa__cors": "^2.2.1",
"accepts": "^1.3.5", "accepts": "^1.3.5",
"apollo-server-core": "2.1.0-alpha.10", "apollo-server-core": "file:../apollo-server-core",
"apollo-upload-server": "^5.0.0",
"graphql-subscriptions": "^0.5.8", "graphql-subscriptions": "^0.5.8",
"graphql-tools": "^3.0.4", "graphql-tools": "^3.0.4",
"iterall": "^1.2.2", "iterall": "^1.2.2",
@ -52,37 +50,9 @@
"type-is": "^1.6.16" "type-is": "^1.6.16"
}, },
"devDependencies": { "devDependencies": {
"@types/koa-multer": "1.0.0", "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
"@types/koa-router": "7.0.31",
"apollo-datasource-rest": "0.1.0",
"apollo-server-integration-testsuite": "2.0.0",
"form-data": "2.3.2",
"koa-multer": "1.0.2",
"node-fetch": "2.2.0"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"jest": {
"testEnvironment": "node",
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -12,7 +12,7 @@ import * as typeis from 'type-is';
import { graphqlKoa } from './koaApollo'; import { graphqlKoa } from './koaApollo';
import { processRequest as processFileUploads } from 'apollo-upload-server'; import { processRequest as processFileUploads } from '@apollographql/apollo-upload-server';
export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core'; export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core';
import { GraphQLOptions, FileUploadOptions } from 'apollo-server-core'; import { GraphQLOptions, FileUploadOptions } from 'apollo-server-core';

View file

@ -1,10 +1,12 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist",
"lib": ["es2017", "esnext.asynciterable", "dom"] "noImplicitAny": false,
"strictNullChecks": false,
"noImplicitReturns": false
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "apollo-server-lambda", "name": "apollo-server-lambda",
"version": "2.0.0", "version": "2.0.6",
"description": "Production-ready Node.js GraphQL server for AWS Lambda", "description": "Production-ready Node.js GraphQL server for AWS Lambda",
"keywords": [ "keywords": [
"GraphQL", "GraphQL",
@ -27,44 +27,18 @@
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepublish": "npm run clean && npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"dependencies": { "dependencies": {
"@apollographql/graphql-playground-html": "^1.6.0", "@apollographql/graphql-playground-html": "^1.6.0",
"apollo-server-core": "2.0.0", "apollo-server-core": "file:../apollo-server-core",
"apollo-server-env": "2.0.0", "apollo-server-env": "file:../apollo-server-env",
"graphql-tools": "^3.0.4" "graphql-tools": "^3.0.4"
}, },
"devDependencies": { "devDependencies": {
"@types/aws-lambda": "8.10.10", "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
"apollo-server-integration-testsuite": "2.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"jest": {
"testEnvironment": "node",
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -44,7 +44,7 @@ export class ApolloServer extends ApolloServerBase {
} }
public createHandler({ cors }: CreateHandlerOptions = { cors: undefined }) { public createHandler({ cors }: CreateHandlerOptions = { cors: undefined }) {
const corsHeaders = {}; const corsHeaders: lambda.APIGatewayProxyResult['headers'] = {};
if (cors) { if (cors) {
if (cors.methods) { if (cors.methods) {
@ -119,8 +119,13 @@ export class ApolloServer extends ApolloServerBase {
if (this.playgroundOptions && event.httpMethod === 'GET') { if (this.playgroundOptions && event.httpMethod === 'GET') {
const acceptHeader = event.headers['Accept'] || event.headers['accept']; const acceptHeader = event.headers['Accept'] || event.headers['accept'];
if (acceptHeader && acceptHeader.includes('text/html')) { if (acceptHeader && acceptHeader.includes('text/html')) {
const path =
event.path ||
(event.requestContext && event.requestContext.path) ||
'/';
const playgroundRenderPageOptions: PlaygroundRenderPageOptions = { const playgroundRenderPageOptions: PlaygroundRenderPageOptions = {
endpoint: event.requestContext.path, endpoint: path,
...this.playgroundOptions, ...this.playgroundOptions,
}; };

View file

@ -42,9 +42,9 @@ export function graphqlLambda(
method: event.httpMethod, method: event.httpMethod,
options: options, options: options,
query: query:
event.httpMethod === 'POST' event.httpMethod === 'POST' && event.body
? JSON.parse(event.body) ? JSON.parse(event.body)
: (event.queryStringParameters as any), : event.queryStringParameters,
request: { request: {
url: event.path, url: event.path,
method: event.httpMethod, method: event.httpMethod,

View file

@ -1,10 +1,9 @@
{ {
"extends": "../../tsconfig.json", "extends": "../../tsconfig",
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./dist", "outDir": "./dist"
"lib": ["es2017", "esnext.asynciterable", "dom"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] "exclude": ["**/__tests__", "**/__mocks__"]
} }

View file

@ -5,11 +5,9 @@
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"clean": "rm -rf dist",
"compile": "tsc", "compile": "tsc",
"coverage": "jest --coverage", "prepare": "npm run clean && npm run compile"
"prepare": "npm run compile",
"test": "jest --verbose",
"watch": "tsc -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -30,39 +28,14 @@
}, },
"homepage": "https://github.com/apollographql/apollo-server#readme", "homepage": "https://github.com/apollographql/apollo-server#readme",
"dependencies": { "dependencies": {
"@apollographql/apollo-upload-server": "^5.0.3",
"@apollographql/graphql-playground-html": "^1.6.0",
"accept": "^3.0.2", "accept": "^3.0.2",
"apollo-server-core": "2.1.0-alpha.10", "apollo-server-core": "file:../apollo-server-core",
"apollo-upload-server": "^5.0.0",
"graphql-playground-html": "^1.6.0",
"iterall": "^1.2.2", "iterall": "^1.2.2",
"micro": "^9.3.2" "micro": "^9.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/micro": "7.3.1", "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite"
"apollo-server-integration-testsuite": "2.0.0",
"request-promise": "4.2.2",
"test-listen": "1.1.0"
},
"jest": {
"testEnvironment": "node",
"transform": {
"^.+\\.(ts|js)$": "ts-jest"
},
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testRegex": "src/__tests__/.*$",
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/lib/",
"test-utils"
],
"globals": {
"ts-jest": {
"skipBabel": true
}
}
} }
} }

View file

@ -1,8 +1,8 @@
import { ApolloServerBase, GraphQLOptions } from 'apollo-server-core'; import { ApolloServerBase, GraphQLOptions } from 'apollo-server-core';
import { processRequest as processFileUploads } from 'apollo-upload-server'; import { processRequest as processFileUploads } from '@apollographql/apollo-upload-server';
import { ServerResponse } from 'http'; import { ServerResponse } from 'http';
import { send } from 'micro'; import { send } from 'micro';
import { renderPlaygroundPage } from 'graphql-playground-html'; import { renderPlaygroundPage } from '@apollographql/graphql-playground-html';
import { parseAll } from 'accept'; import { parseAll } from 'accept';
import { graphqlMicro } from './microApollo'; import { graphqlMicro } from './microApollo';

Some files were not shown because too many files have changed in this diff Show more