-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add multipart subscription network adapters for Relay and urql (#…
- Loading branch information
Showing
12 changed files
with
261 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
## API Report File for "@apollo/client" | ||
|
||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). | ||
```ts | ||
|
||
import type { GraphQLResponse } from 'relay-runtime'; | ||
import { Observable } from 'relay-runtime'; | ||
import type { RequestParameters } from 'relay-runtime'; | ||
|
||
// Warning: (ae-forgotten-export) The symbol "CreateMultipartSubscriptionOptions" needs to be exported by the entry point index.d.ts | ||
// Warning: (ae-forgotten-export) The symbol "OperationVariables" needs to be exported by the entry point index.d.ts | ||
// | ||
// @public (undocumented) | ||
export function createFetchMultipartSubscription(uri: string, { fetch: preferredFetch, headers }?: CreateMultipartSubscriptionOptions): (operation: RequestParameters, variables: OperationVariables) => Observable<GraphQLResponse>; | ||
|
||
// @public (undocumented) | ||
type CreateMultipartSubscriptionOptions = { | ||
fetch?: WindowOrWorkerGlobalScope["fetch"]; | ||
headers?: Record<string, string>; | ||
}; | ||
|
||
// @public (undocumented) | ||
type OperationVariables = Record<string, any>; | ||
|
||
// (No @packageDocumentation comment for this package) | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
## API Report File for "@apollo/client" | ||
|
||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). | ||
```ts | ||
|
||
import { Observable } from 'zen-observable-ts'; | ||
|
||
// Warning: (ae-forgotten-export) The symbol "CreateMultipartSubscriptionOptions" needs to be exported by the entry point index.d.ts | ||
// | ||
// @public (undocumented) | ||
export function createFetchMultipartSubscription(uri: string, { fetch: preferredFetch, headers }?: CreateMultipartSubscriptionOptions): ({ query, variables, }: { | ||
query?: string | undefined; | ||
variables: undefined | Record<string, any>; | ||
}) => Observable<unknown>; | ||
|
||
// @public (undocumented) | ||
type CreateMultipartSubscriptionOptions = { | ||
fetch?: WindowOrWorkerGlobalScope["fetch"]; | ||
headers?: Record<string, string>; | ||
}; | ||
|
||
// (No @packageDocumentation comment for this package) | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
"@apollo/client": minor | ||
--- | ||
|
||
Add multipart subscription network adapters for Relay and urql | ||
|
||
### Relay | ||
|
||
```tsx | ||
import { createFetchMultipartSubscription } from "@apollo/client/utilities/subscriptions/relay"; | ||
import { Environment, Network, RecordSource, Store } from "relay-runtime"; | ||
|
||
const fetchMultipartSubs = createFetchMultipartSubscription( | ||
"http://localhost:4000" | ||
); | ||
|
||
const network = Network.create(fetchQuery, fetchMultipartSubs); | ||
|
||
export const RelayEnvironment = new Environment({ | ||
network, | ||
store: new Store(new RecordSource()), | ||
}); | ||
``` | ||
|
||
### Urql | ||
|
||
```tsx | ||
import { createFetchMultipartSubscription } from "@apollo/client/utilities/subscriptions/urql"; | ||
import { Client, fetchExchange, subscriptionExchange } from "@urql/core"; | ||
|
||
const url = "http://localhost:4000"; | ||
|
||
const multipartSubscriptionForwarder = createFetchMultipartSubscription( | ||
url | ||
); | ||
|
||
const client = new Client({ | ||
url, | ||
exchanges: [ | ||
fetchExchange, | ||
subscriptionExchange({ | ||
forwardSubscription: multipartSubscriptionForwarder, | ||
}), | ||
], | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Observable } from "relay-runtime"; | ||
import type { RequestParameters, GraphQLResponse } from "relay-runtime"; | ||
import { | ||
handleError, | ||
readMultipartBody, | ||
} from "../../../link/http/parseAndCheckHttpResponse.js"; | ||
import { maybe } from "../../index.js"; | ||
import { serializeFetchParameter } from "../../../core/index.js"; | ||
|
||
import type { OperationVariables } from "../../../core/index.js"; | ||
import type { Body } from "../../../link/http/selectHttpOptionsAndBody.js"; | ||
import { generateOptionsForMultipartSubscription } from "../shared.js"; | ||
import type { CreateMultipartSubscriptionOptions } from "../shared.js"; | ||
|
||
const backupFetch = maybe(() => fetch); | ||
|
||
export function createFetchMultipartSubscription( | ||
uri: string, | ||
{ fetch: preferredFetch, headers }: CreateMultipartSubscriptionOptions = {} | ||
) { | ||
return function fetchMultipartSubscription( | ||
operation: RequestParameters, | ||
variables: OperationVariables | ||
): Observable<GraphQLResponse> { | ||
const body: Body = { | ||
operationName: operation.name, | ||
variables, | ||
query: operation.text || "", | ||
}; | ||
const options = generateOptionsForMultipartSubscription(headers || {}); | ||
|
||
return Observable.create((sink) => { | ||
try { | ||
options.body = serializeFetchParameter(body, "Payload"); | ||
} catch (parseError) { | ||
sink.error(parseError); | ||
} | ||
|
||
const currentFetch = preferredFetch || maybe(() => fetch) || backupFetch; | ||
const observerNext = sink.next.bind(sink); | ||
|
||
currentFetch!(uri, options) | ||
.then((response) => { | ||
const ctype = response.headers?.get("content-type"); | ||
|
||
if (ctype !== null && /^multipart\/mixed/i.test(ctype)) { | ||
return readMultipartBody(response, observerNext); | ||
} | ||
|
||
sink.error(new Error("Expected multipart response")); | ||
}) | ||
.then(() => { | ||
sink.complete(); | ||
}) | ||
.catch((err: any) => { | ||
handleError(err, sink); | ||
}); | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { fallbackHttpConfig } from "../../link/http/selectHttpOptionsAndBody.js"; | ||
|
||
export type CreateMultipartSubscriptionOptions = { | ||
fetch?: WindowOrWorkerGlobalScope["fetch"]; | ||
headers?: Record<string, string>; | ||
}; | ||
|
||
export function generateOptionsForMultipartSubscription( | ||
headers: Record<string, string> | ||
) { | ||
const options: { headers: Record<string, any>; body?: string } = { | ||
...fallbackHttpConfig.options, | ||
headers: { | ||
...(headers || {}), | ||
...fallbackHttpConfig.headers, | ||
accept: | ||
"multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/json", | ||
}, | ||
}; | ||
return options; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Observable } from "../../index.js"; | ||
import { | ||
handleError, | ||
readMultipartBody, | ||
} from "../../../link/http/parseAndCheckHttpResponse.js"; | ||
import { maybe } from "../../index.js"; | ||
import { serializeFetchParameter } from "../../../core/index.js"; | ||
import type { Body } from "../../../link/http/selectHttpOptionsAndBody.js"; | ||
import { generateOptionsForMultipartSubscription } from "../shared.js"; | ||
import type { CreateMultipartSubscriptionOptions } from "../shared.js"; | ||
|
||
const backupFetch = maybe(() => fetch); | ||
|
||
export function createFetchMultipartSubscription( | ||
uri: string, | ||
{ fetch: preferredFetch, headers }: CreateMultipartSubscriptionOptions = {} | ||
) { | ||
return function multipartSubscriptionForwarder({ | ||
query, | ||
variables, | ||
}: { | ||
query?: string; | ||
variables: undefined | Record<string, any>; | ||
}) { | ||
const body: Body = { variables, query }; | ||
const options = generateOptionsForMultipartSubscription(headers || {}); | ||
|
||
return new Observable((observer) => { | ||
try { | ||
options.body = serializeFetchParameter(body, "Payload"); | ||
} catch (parseError) { | ||
observer.error(parseError); | ||
} | ||
|
||
const currentFetch = preferredFetch || maybe(() => fetch) || backupFetch; | ||
const observerNext = observer.next.bind(observer); | ||
|
||
currentFetch!(uri, options) | ||
.then((response) => { | ||
const ctype = response.headers?.get("content-type"); | ||
|
||
if (ctype !== null && /^multipart\/mixed/i.test(ctype)) { | ||
return readMultipartBody(response, observerNext); | ||
} | ||
|
||
observer.error(new Error("Expected multipart response")); | ||
}) | ||
.then(() => { | ||
observer.complete(); | ||
}) | ||
.catch((err: any) => { | ||
handleError(err, observer); | ||
}); | ||
}); | ||
}; | ||
} |