Skip to content

Commit

Permalink
feat(client): url option accepts a function or a Promise (enisdenjo…
Browse files Browse the repository at this point in the history
…#143)

Closes enisdenjo#145, closes enisdenjo#146

Co-authored-by: Denis Badurina <denis@domonda.com>
  • Loading branch information
edwardfeng-db and enisdenjo committed Mar 25, 2021
1 parent 62f2089 commit 76f522f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
10 changes: 9 additions & 1 deletion docs/interfaces/client.clientoptions.md
Expand Up @@ -213,10 +213,18 @@ ___

### url

**url**: *string*
**url**: *string* \| () => *string* \| *Promise*<string\>

URL of the GraphQL over WebSocket Protocol compliant server to connect.

If the option is a function, it will be called on every WebSocket connection attempt.
Returning a promise is supported too and the connecting phase will stall until it
resolves with the URL.

A good use-case for having a function is when using the URL for authentication,
where subsequent reconnects (due to auth) may have a refreshed identity token in
the URL.

___

### webSocketImpl
Expand Down
19 changes: 16 additions & 3 deletions src/client.ts
Expand Up @@ -81,8 +81,18 @@ export type EventListener<E extends Event> = E extends EventConnecting

/** Configuration used for the GraphQL over WebSocket client. */
export interface ClientOptions {
/** URL of the GraphQL over WebSocket Protocol compliant server to connect. */
url: string;
/**
* URL of the GraphQL over WebSocket Protocol compliant server to connect.
*
* If the option is a function, it will be called on every WebSocket connection attempt.
* Returning a promise is supported too and the connecting phase will stall until it
* resolves with the URL.
*
* A good use-case for having a function is when using the URL for authentication,
* where subsequent reconnects (due to auth) may have a refreshed identity token in
* the URL.
*/
url: string | (() => Promise<string> | string);
/**
* Optional parameters, passed through the `payload` field with the `ConnectionInit` message,
* that the client specifies when establishing a connection with the server. You can use this
Expand Down Expand Up @@ -330,7 +340,10 @@ export function createClient(options: ClientOptions): Client {
}

emitter.emit('connecting');
const socket = new WebSocketImpl(url, GRAPHQL_TRANSPORT_WS_PROTOCOL);
const socket = new WebSocketImpl(
typeof url === 'function' ? await url() : url,
GRAPHQL_TRANSPORT_WS_PROTOCOL,
);

socket.onerror = (err) => {
// we let the onclose reject the promise for correct retry handling
Expand Down
13 changes: 13 additions & 0 deletions src/tests/client.ts
Expand Up @@ -140,6 +140,19 @@ it('should use the provided WebSocket implementation', async () => {
await server.waitForClient();
});

it('should accept a function for the url', async () => {
const { url, ...server } = await startTServer();

createClient({
url: () => Promise.resolve(url),
retryAttempts: 0,
onNonLazyError: noop,
lazy: false,
});

await server.waitForClient();
});

it('should not accept invalid WebSocket implementations', async () => {
const { url } = await startTServer();

Expand Down

0 comments on commit 76f522f

Please sign in to comment.