Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to AS3 docs that are not related to differences from AS2 #5340

Merged
merged 14 commits into from
Jul 9, 2021
2 changes: 1 addition & 1 deletion docs/source/data/data-sources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ flowchart LR;

## Open-source implementations

All data source implementations extend the generic [`DataSource` abstract class](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-datasource/src/index.ts), which is included in the `apollo-server` library. Subclasses define whatever logic is required to communicate with a particular store or API.
All data source implementations extend the generic [`DataSource` abstract class](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-datasource/src/index.ts), which is included in the `apollo-datasource` package. Subclasses of a `DataSource` should define whatever logic is required to communicate with a particular store or API.

Apollo and the larger community maintain the following open-source implementatons:

Expand Down
12 changes: 9 additions & 3 deletions docs/source/data/resolvers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,13 @@ Note that you can define your resolvers across as many different files and objec

## Resolver chains

Whenever a query asks for a field that contains an object type, the query _also_ asks for _at least one field_ of that object (if it didn't, there would be no reason to include the object in the query). A query always "bottoms out" on fields that contain either a scalar or a list of scalars.
Whenever a query asks for a field that contains an object type, the query _also_ asks for _at least one field_ of that object (if it didn't, there would be no reason to include the object in the query). A query always "bottoms out" on fields that contain either a scalar or an enum, of any list depth and nullability, for example:

```graphql
type Product {
variants: [String!]
}
```

Therefore, whenever Apollo Server _resolves_ a field that contains an object type, it always then resolves one or more fields of that object. Those subfields might in turn _also_ contain object types. Depending on your schema, this object-field pattern can continue to an arbitrary depth, creating what's called a **resolver chain**.

Expand Down Expand Up @@ -388,7 +394,7 @@ const server = new ApolloServer({
}
```

> The fields of the object passed to your `context` function differ if you're using middleware besides Express. [See the API reference for details.](/api/apollo-server/#middleware-specific-context-fields)
> This example assumes you are using either the `apollo-server` or `apollo-server-express` package, both of which use Express. The fields of the object passed to your `context` function may differ if you're using middleware other than Express. [See the API reference for details.](/api/apollo-server/#middleware-specific-context-fields) For more information on middleware in general, see the [integrations page](/integrations/middleware).

Context initialization can be asynchronous, allowing database connections and other operations to complete:

Expand All @@ -411,7 +417,7 @@ A resolver function's return value is treated differently by Apollo Server depen
|---|---|
| Scalar / object | <p>A resolver can return a single value or an object, as shown in [Defining a resolver](#defining-a-resolver). This return value is passed down to any nested resolvers via the `parent` argument.</p> |
| `Array` | <p>Return an array if and only if your schema indicates that the resolver's associated field contains a list.</p><p>After you return an array, Apollo Server executes nested resolvers for each item in the array. </p>|
| `null` / `undefined` | <p>Indicates that the value for the field could not be found.</p> <p>If your schema indicates that this resolver's field is nullable, then the operation result has a `null` value at the field's position.</p><p>If this resolver's field is _not_ nullable, Apollo Server sets the field's _parent_ to `null`. If necessary, this process continues up the resolver chain until it reaches a field that _is_ nullable. This ensures that a response never includes a `null` value for a non-nullable field.</p>|
| `null` / `undefined` | <p>Indicates that the value for the field could not be found.</p> <p>If your schema indicates that this resolver's field is nullable, then the operation result has a `null` value at the field's position.</p><p>If this resolver's field is _not_ nullable, Apollo Server sets the field's _parent_ to `null`. If necessary, this process continues up the resolver chain until it reaches a field that _is_ nullable. This ensures that a response never includes a `null` value for a non-nullable field. When this happens, the response's `errors` property will be populated with relevant errors concerning the nullability of that field.</p>|
| [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) | <p>Resolvers often perform asynchronous actions, such as fetching from a database or back-end API. To support this, a resolver can return a promise that resolves to any other supported return type.</p> |


Expand Down
26 changes: 11 additions & 15 deletions docs/source/monitoring/health-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ title: Health checks
description: Determining the health status of the Apollo Server
---

Health checks are often used by load balancers to determine if a server is available and ready to start serving traffic. By default, Apollo Server provides a health check endpoint at `/.well-known/apollo/server-health` which returns a 200 status code if the server has started.
Health checks are often used by load balancers to determine if a server is available and ready to start serving traffic. By default, Apollo Server provides a health check endpoint at `/.well-known/apollo/server-health` which returns a 200 status code if the server has started.

This basic health check may not be comprehensive enough for some applications and depending on individual circumstances, it may be beneficial to provide a more thorough implementation by defining an `onHealthCheck` function to the `ApolloServer` constructor options. If defined, this `onHealthCheck` function should return a `Promise` which _rejects_ if there is an error, or _resolves_ if the server is deemed _ready_. A `Promise` _rejection_ will result in an HTTP status code of 503, and a _resolution_ will result in an HTTP status code of 200, which is generally desired by most health-check tooling (e.g. Kubernetes, AWS, etc.).
This basic health check may not be comprehensive enough for some applications and depending on individual circumstances, it may be beneficial to provide a more thorough implementation by defining an `onHealthCheck` function to the `ApolloServer` constructor options. If defined, this `onHealthCheck` async function should return if the server is deemed _ready_ or `throw` if there is an error. Returning (resolving the `Promise`) will result in an HTTP status code of 200, which is generally desired by most health-check tooling (e.g. Kubernetes, AWS, etc.), while `throw`ing (rejecting the `Promise`) will result in an HTTP status code of 503.

> **Note:** Alternatively, the `onHealthCheck` can be defined as an `async` function which `throw`s if it encounters an error and returns when conditions are considered normal.

```js{10-19}
const { ApolloServer, gql } = require('apollo-server');
```js{10-17}
import { ApolloServer, gql } from 'apollo-server';

// Undefined for brevity.
const typeDefs = gql``;
Expand All @@ -19,15 +17,13 @@ const resolvers = {};
const server = new ApolloServer({
typeDefs,
resolvers,
onHealthCheck: () => {
return new Promise((resolve, reject) => {
// Replace the `true` in this conditional with more specific checks!
if (true) {
resolve();
} else {
reject();
}
});
async onHealthCheck() {
// Replace the `true` in this conditional with more specific checks!
if (true) {
return;
} else {
throw new Error('...');
}
},
});

Expand Down
4 changes: 3 additions & 1 deletion docs/source/performance/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: Configure caching behavior on a per-field basis

> **New in Apollo Server 3**: You must manually define the `@cacheControl` directive in your schema to use static cache hints. [See below.](#in-your-schema-static)

FIXME should note that federation doesn't support caching well though maybe link to something that explains workarounds?

Apollo Server enables you to define cache control settings (`maxAge` and `scope`) for each field in your schema:

```graphql{5,7}
Expand Down Expand Up @@ -306,7 +308,7 @@ If you run Apollo Server behind a CDN or another caching proxy, you can configur

Because CDNs and caching proxies only cache GET requests (not POST requests, which Apollo Client sends for all operations by default), we recommend enabling [automatic persisted queries](./apq/) and the [`useGETForHashedQueries` option](./apq/) in Apollo Client.

Alternatively, you can set the `useGETForQueries` option of [HttpLink](https://www.apollographql.com/docs/react/api/link/apollo-link-http) in your `ApolloClient` instance, but **this is less secure** because your query string and GraphQL variables are sent as plaintext URL query parameters.
Alternatively, you can set the `useGETForQueries` option of [HttpLink](https://www.apollographql.com/docs/react/api/link/apollo-link-http) in your `ApolloClient` instance, but **this may be less secure** because your query string and GraphQL variables are sent as plaintext URL query parameters which are more likely to be saved in logs by some server or proxy between the user and your GraphQL server. FIXME I tried to improve this but it still doesn't make that much sense because `useGETForHashedQueries` certainly puts variables in the URL... I think the real reason to avoid useGETForQueries is that GETs have a length limit!

## Disabling cache control

Expand Down
2 changes: 2 additions & 0 deletions docs/source/proxy-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Configuring proxy settings for outgoing requests

Certain features of the Apollo platform require Apollo Server to make outgoing requests to Apollo Studio. These include:

FIXME: could mention usage reporting and schema reporting too, though for them should just override fetcher...

* Managed federation
* Operation registry

Expand Down
28 changes: 18 additions & 10 deletions docs/source/schema/custom-scalars.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ To define a custom scalar, add it to your schema like so:
scalar MyCustomScalar
```

Object types in your schema can now contain fields of type `MyCustomScalar`. However, Apollo Server still needs to know how to interact with values of this new scalar type.
You can now use `MyCustomScalar` in your schema anywhere you can use a default scalar (e.g., as the type of an object field, input type field, or argument).

However, Apollo Server still needs to know how to interact with values of this new scalar type.

## Defining custom scalar logic

Expand Down Expand Up @@ -70,13 +72,13 @@ In the example above, the `Date` scalar is represented on the backend by the `Da

### `parseValue`

The `parseValue` method converts the scalar's `serialize`d JSON value to its back-end representation before it's added to a resolver's `args`.
The `parseValue` method converts the scalar's JSON value to its back-end representation before it's added to a resolver's `args`.

Apollo Server calls this method when the scalar is provided by a client as a [GraphQL variable](https://graphql.org/learn/queries/#variables) for an argument. (When a scalar is provided as a hard-coded argument in the operation string, [`parseLiteral`](#parseliteral) is called instead.)

### `parseLiteral`

When an incoming query string includes the scalar as a hard-coded argument value, that value is part of the query document's abstract syntax tree (AST). Apollo Server calls the `parseLiteral` method to convert the value's AST representation (which is always a string) to the scalar's back-end representation.
When an incoming query string includes the scalar as a hard-coded argument value, that value is part of the query document's abstract syntax tree (AST). Apollo Server calls the `parseLiteral` method to convert the value's AST representation (this always starts as a string that you can parse as needed) to the scalar's back-end representation.
StephenBarlow marked this conversation as resolved.
Show resolved Hide resolved

In [the example above](#example-the-date-scalar), `parseLiteral` converts the AST value from a string to an integer, and _then_ converts from integer to `Date` to match the result of `parseValue`.

Expand Down Expand Up @@ -120,25 +122,26 @@ const server = new ApolloServer({

In this example, we create a custom scalar called `Odd` that can only contain odd integers:

```js{19-30}
```js:title=index.js
const { ApolloServer, gql, UserInputError } = require('apollo-server');
const { GraphQLScalarType, Kind } = require('graphql');

// Basic schema
const typeDefs = gql`
scalar Odd

type MyType {
oddValue: Odd
type Query {
# Echoes the provided odd integer
echoOdd(odd: Odd!): Odd!
}
`;

// Validation function
// Validation function for checking "oddness"
function oddValue(value) {
if (typeof value === "number" && value % 2 === 1) {
if (typeof value === "number" && Number.isInteger(value) && value % 2 !== 0) {
return value;
}
throw new UserInputError("provided value is not an odd number");
throw new UserInputError("Provided value is not an odd integer");
}

const resolvers = {
Expand All @@ -151,9 +154,14 @@ const resolvers = {
if (ast.kind === Kind.INT) {
return oddValue(parseInt(ast.value, 10));
}
return null;
throw new UserInputError("Provided value is not an odd integer");
},
}),
Query: {
echoOdd(_, {odd}) {
return odd;
}
}
};

const server = new ApolloServer({ typeDefs, resolvers });
Expand Down
1 change: 1 addition & 0 deletions docs/source/schema/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This example shows the `@deprecated` directive, which is a [default directive](#
Each directive can only appear in _certain_ locations within a GraphQL schema or operation. These locations are listed in the directive's definition.

For example, here's the GraphQL spec's definition of the `@deprecated` directive:
FIXME I believe this is now outdated as `@deprecated` can appear in more places now.

```graphql
directive @deprecated(
Expand Down
Loading