Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

spec-compliant GET support #490

Merged
merged 5 commits into from
Feb 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/apollo-link-batch-http/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### vNext
- share logic with apollo-link-http through apollo-link-http-core [PR#364](https://github.com/apollographql/apollo-link/pull/364)
- remove apollo-fetch [PR#364](https://github.com/apollographql/apollo-link/pull/364)
- GET is no longer supported for batching (it never worked anyway) [PR#490](https://github.com/apollographql/apollo-link/pull/490)

### 1.0.5
- ApolloLink upgrade
Expand Down
23 changes: 3 additions & 20 deletions packages/apollo-link-batch-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ http options follow the same structure as the
* `credentials`: a string representing the credentials policy you want for the
fetch call
* `fetchOptions`: any overrides of the fetch options argument to pass to the
fetch call
fetch call. Note that you cannot use batching with the GET HTTP method.

The batching options indicate how operations are batched together, the size of
batches, and the maximum time a batch will wait before automatically being sent
Expand Down Expand Up @@ -89,32 +89,15 @@ The batch http link handles errors on a per batch basis with the same semantics

<h2 id="custom">Custom fetching</h2>

You can use the `fetch` option when creating an http-link to do a lot of custom networking. This is useful if you want to modify the request based on the headers calculated, send the request as a 'GET' via a query string, or calculate the uri based on the operation:

<h3 id="get-request">Sending a GET request</h3>

```js
const customFetch = (uri, options) => {
const { body, ...newOptions } = options;
// turn the object into a query string, try `object-to-querystring` package
const queryString = objectToQuery(JSON.parse(body));
requestedString = uri + queryString;
return fetch(requestedString, newOptions);
};
const link = createBatchHttpLink({
uri: "data",
fetchOptions: { method: "GET" },
fetch: customFetch
});
```
You can use the `fetch` option when creating an http-link to do a lot of custom networking. This is useful if you want to modify the request based on the calculated headers or calculate the uri based on the operation:

<h3 id="custom-auth">Custom auth</h3>

```js
const customFetch = (uri, options) => {
const { header } = Hawk.client.header(
"http://example.com:8000/resource/1?b=1&a=2",
"GET",
"POST",
{ credentials: credentials, ext: "some-app-data" }
);
options.headers.Authorization = header;
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-link-batch-http/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"dependencies": {
"apollo-link": "^1.1.0",
"apollo-link-batch": "^1.0.5",
"apollo-link-http-common": "^0.1.0"
"apollo-link-http-common": "^0.2.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.3 || ^0.13.0"
Expand Down
23 changes: 17 additions & 6 deletions packages/apollo-link-batch-http/src/batchHttpLink.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ApolloLink, Operation, FetchResult, Observable } from 'apollo-link';
import {
serializeFetchBody,
ApolloLink,
Operation,
FetchResult,
Observable,
fromError,
} from 'apollo-link';
import {
serializeFetchParameter,
selectURI,
parseAndCheckHttpResponse,
checkFetcher,
Expand Down Expand Up @@ -102,12 +108,17 @@ export class BatchHttpLink extends ApolloLink {
const body = optsAndBody.map(({ body }) => body);
const options = optsAndBody[0].options;

// There's no spec for using GET with batches.
if (options.method === 'GET') {
return fromError<FetchResult[]>(
new Error('apollo-link-batch-http does not support GET requests'),
);
}

try {
(options as any).body = serializeFetchBody(body);
(options as any).body = serializeFetchParameter(body, 'Payload');
} catch (parseError) {
return new Observable<FetchResult[]>(observer => {
observer.error(parseError);
});
return fromError<FetchResult[]>(parseError);
}

const { controller, signal } = createSignalIfSupported();
Expand Down
4 changes: 4 additions & 0 deletions packages/apollo-link-http-common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Change log

### v0.2.0
- rename serializeFetchBody to serializeFetchParameter and take a label argument
2 changes: 1 addition & 1 deletion packages/apollo-link-http-common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-link-http-common",
"version": "0.1.0",
"version": "0.2.0",
"description":
"Http utilities for Apollo Link shared across all links using http",
"main": "./lib/bundle.umd.js",
Expand Down
8 changes: 4 additions & 4 deletions packages/apollo-link-http-common/src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
checkFetcher,
selectHttpOptionsAndBody,
selectURI,
serializeFetchBody,
serializeFetchParameter,
fallbackHttpConfig,
} from '../index';

Expand Down Expand Up @@ -191,19 +191,19 @@ describe('Common Http functions', () => {
});
});

describe('serializeFetchBody', () => {
describe('serializeFetchParameter', () => {
it('throws a parse error on an unparsable body', () => {
const b = {};
const a = { b };
(b as any).a = a;

expect(() => serializeFetchBody(b)).toThrow();
expect(() => serializeFetchParameter(b, 'Label')).toThrow(/Label/);
});

it('returns a correctly parsed body', () => {
const body = { no: 'thing' };

expect(serializeFetchBody(body)).toEqual('{"no":"thing"}');
expect(serializeFetchParameter(body, 'Label')).toEqual('{"no":"thing"}');
});
});

Expand Down
20 changes: 14 additions & 6 deletions packages/apollo-link-http-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ export interface UriFunction {
(operation: Operation): string;
}

// The body of a GraphQL-over-HTTP-POST request.
export interface Body {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may be able to have Body be an interface that extends Partial, see this SO. GraphQLRequest is exported from apollo-link

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query is a string rather than a DocumentNode (and there's no context), so I don't think that'll work?

In my experience over the entire open source and commercial Apollo codebase, guessing what type is going to be in a field or variable called query is the most challenging part :)

query?: string;
operationName?: string;
variables?: Record<string, any>;
extensions?: Record<string, any>;
}

export interface HttpOptions {
/**
* The URI to use when fetching operations.
Expand Down Expand Up @@ -220,7 +228,7 @@ export const selectHttpOptionsAndBody = (

//The body depends on the http options
const { operationName, extensions, variables, query } = operation;
const body = { operationName, variables };
const body: Body = { operationName, variables };

if (http.includeExtensions) (body as any).extensions = extensions;

Expand All @@ -233,18 +241,18 @@ export const selectHttpOptionsAndBody = (
};
};

export const serializeFetchBody = body => {
let serializedBody;
export const serializeFetchParameter = (p, label) => {
Copy link
Contributor

@evans evans Feb 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaydenseric This is going to be a breaking change for [email protected]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this OK? I thought this hadn't been released yet so it was an OK interface to break without documenting.

Copy link

@jaydenseric jaydenseric Feb 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok if the change is documented in a changelog entry, and a new version of apollo-link-http-common is published with a semver major (breaking change).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't realize Evans had published a non alpha version of the package.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Evans, should I just revert the name change or something, or bump to 0.2.0?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you keep the breaking changes, please bump to v1.0.0, breaking changes in semver minor releases are the devil.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glasser We can bump to v1.0.0, since it will make Jayden's life easier. I'm not worried about having the version number bloat and it might force better practice. The plan for apollo-link-common-http was to be a semi private API(without documentation due to overhead) that developers of links can look at if they want to align with apollo-link-http and apollo-link-batch-http. In that goal I think attempting to follow SemVer would be make keeping up with the changes easier

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I am wrong ^. Let's do v0.2, since we are pre v1.0 SemVer says that a breaking change should be a minor version. Also it looks like we should be okay for Jayden's upload-client

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backwards compatibility, you should probably already be 1.0.0.

All 3 things should be assumed to be true for every npm package that can be publically installed. There are only upsides and no downsides to bumping the major version number if there is ever a breaking change.

FB in particular is the absolute worst for this. react jumping from v0.14 to v15 was an admission of guilt they had it wrong for 14 major versions. graphql being a v0.x causes great disruption to the ecosystem every update.

let serialized;
try {
serializedBody = JSON.stringify(body);
serialized = JSON.stringify(p);
} catch (e) {
const parseError = new Error(
`Network request failed. Payload is not serializable: ${e.message}`,
`Network request failed. ${label} is not serializable: ${e.message}`,
) as ClientParseError;
parseError.parseError = e;
throw parseError;
}
return serializedBody;
return serialized;
};

//selects "/graphql" by default
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-link-http/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### vNEXT
- move logic to apollo-link-http-core [PR#364](https://github.com/apollographql/apollo-link/pull/364)
- follow the spec properly for GET requests [PR#490](https://github.com/apollographql/apollo-link/pull/490)

### 1.3.3
- ApolloLink upgrade
Expand Down
27 changes: 6 additions & 21 deletions packages/apollo-link-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Link ecosystem and how to use this link with libraries like Apollo Client and
graphql-tools, or as a standalone client.

The http link is a terminating link that fetches GraphQL results from a GraphQL
endpoint over an http connection. The http link support both POST and GET
endpoint over an http connection. The http link supports both POST and GET
requests with the ability change the http options on a per query basis. This
can be used for authentication, persisted queries, dynamic uris, and other
granular updates.
Expand Down Expand Up @@ -42,7 +42,9 @@ The HTTP Link relies on having `fetch` present in your runtime environment. If y

<h2 id="context">Context</h2>

The Http Link uses the `headers` field on the context to allow passing headers to the HTTP request. It also supports the `credentials` field for defining credentials policy, `uri` for changing the endpoint dynamically, and `fetchOptions` to allow generic fetch overrides (i.e. method: "GET"). These options will override the same key if passed when creating the the link.
The Http Link uses the `headers` field on the context to allow passing headers to the HTTP request. It also supports the `credentials` field for defining credentials policy, `uri` for changing the endpoint dynamically, and `fetchOptions` to allow generic fetch overrides (i.e. `method: "GET"`). These options will override the same key if passed when creating the the link.

Note that if you set `fetchOptions.method` to `GET`, the http link will follow the [standard GraphQL HTTP GET encoding](http://graphql.org/learn/serving-over-http/#get-request): the query, variables, operation name, and extensions will be passed as query parameters rather than in the HTTP request body.

This link also attaches the response from the `fetch` operation on the context as `response` so you can access it from within another link.

Expand Down Expand Up @@ -146,32 +148,15 @@ All error types inherit the `name`, `message`, and nullable `stack` properties f

<h2 id="custom">Custom fetching</h2>

You can use the `fetch` option when creating an http-link to do a lot of custom networking. This is useful if you want to modify the request based on the headers calculated, send the request as a 'GET' via a query string, or calculate the uri based on the operation:

<h3 id="get-request">Sending a GET request</h3>

```js
const customFetch = (uri, options) => {
const { body, ...newOptions } = options;
// turn the object into a query string, try `object-to-querystring` package
const queryString = objectToQuery(JSON.parse(body));
requestedString = uri + queryString;
return fetch(requestedString, newOptions);
};
const link = createHttpLink({
uri: "data",
fetchOptions: { method: "GET" },
fetch: customFetch
});
```
You can use the `fetch` option when creating an http-link to do a lot of custom networking. This is useful if you want to modify the request based on the calculated headers or calculate the uri based on the operation:

<h3 id="custom-auth">Custom auth</h3>

```js
const customFetch = (uri, options) => {
const { header } = Hawk.client.header(
"http://example.com:8000/resource/1?b=1&a=2",
"GET",
"POST",
{ credentials: credentials, ext: "some-app-data" }
);
options.headers.Authorization = header;
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-link-http/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
"dependencies": {
"apollo-link": "^1.1.0",
"apollo-link-http-common": "^0.1.0"
"apollo-link-http-common": "^0.2.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0"
Expand Down
Loading