Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Add fromJson and toJson options to HTTP transport
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva committed Sep 10, 2024
1 parent 0571c4c commit ea59901
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/slow-dragons-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solana/rpc-transport-http': patch
---

Add `fromJson` and `toJson` options to the HTTP transport
8 changes: 8 additions & 0 deletions packages/rpc-transport-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ const balances = await Promise.allSettled(
);
```

##### `fromJson`

An optional function that takes the response as a JSON string and converts it to a JSON value. The request payload is also provided as a second argument. When not provided, the JSON value will be accessed via the `response.json()` method of the fetch API.

##### `headers`

An object of headers to set on the request. Avoid [forbidden headers](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name). Additionally, the headers `Accept`, `Content-Length`, and `Content-Type` are disallowed.
Expand All @@ -98,6 +102,10 @@ const transport = createHttpTransport({
});
```

##### `toJson`

An optional function that takes the request payload and converts it to a JSON string. When not provided, `JSON.stringify` will be used.

##### `url`

A string representing the target endpoint. In Node, it must be an absolute URL using the `http` or `https` protocol.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { RpcTransport } from '@solana/rpc-spec';

describe('createHttpTransport and `fromJson` function', () => {
let fromJson: jest.Mock;
let fetchSpy: jest.SpyInstance;
let makeHttpRequest: RpcTransport;
beforeEach(async () => {
await jest.isolateModulesAsync(async () => {
fromJson = jest.fn();
fetchSpy = jest.spyOn(globalThis, 'fetch');
fetchSpy.mockResolvedValue({ ok: true, text: () => '{"ok":true}' });
const { createHttpTransport } =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await import('../http-transport');
makeHttpRequest = createHttpTransport({ fromJson, url: 'http://localhost' });
});
});
it('uses the `fromJson` function to parse the response from a JSON string', async () => {
expect.assertions(1);
await makeHttpRequest({ payload: { foo: 123 } });
expect(fromJson).toHaveBeenCalledWith('{"ok":true}', { foo: 123 });
});
it('returns the value parsed by `fromJson`', async () => {
expect.assertions(1);
fromJson.mockReturnValueOnce({ result: 456 });
await expect(makeHttpRequest({ payload: { foo: 123 } })).resolves.toEqual({ result: 456 });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { RpcTransport } from '@solana/rpc-spec';

describe('createHttpTransport and `toJson` function', () => {
let toJson: jest.Mock;
let fetchSpy: jest.SpyInstance;
let makeHttpRequest: RpcTransport;
beforeEach(async () => {
await jest.isolateModulesAsync(async () => {
toJson = jest.fn(value => JSON.stringify(value));
fetchSpy = jest.spyOn(globalThis, 'fetch');
fetchSpy.mockResolvedValue({ json: () => ({ ok: true }), ok: true });
const { createHttpTransport } =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await import('../http-transport');
makeHttpRequest = createHttpTransport({ toJson, url: 'http://localhost' });
});
});
it('uses the `toJson` function to transform the payload to a JSON string', () => {
makeHttpRequest({ payload: { foo: 123 } });
expect(toJson).toHaveBeenCalledWith({ foo: 123 });
});
it('uses passes the JSON string to the fetch API', () => {
toJson.mockReturnValueOnce('{"someAugmented":"jsonString"}');
makeHttpRequest({ payload: { foo: 123 } });
expect(fetchSpy).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
body: '{"someAugmented":"jsonString"}',
}),
);
});
});
9 changes: 7 additions & 2 deletions packages/rpc-transport-http/src/http-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {

type Config = Readonly<{
dispatcher_NODE_ONLY?: Dispatcher;
fromJson?: (rawResponse: string, payload: unknown) => RpcResponse;
headers?: AllowedHttpRequestHeaders;
toJson?: (payload: unknown) => string;
url: string;
}>;

Expand All @@ -32,7 +34,7 @@ export function createHttpTransport(config: Config): RpcTransport {
if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {
warnDispatcherWasSuppliedInNonNodeEnvironment();
}
const { headers, url } = config;
const { fromJson, headers, toJson, url } = config;
if (__DEV__ && headers) {
assertIsAllowedHttpRequestHeaders(headers);
}
Expand All @@ -45,7 +47,7 @@ export function createHttpTransport(config: Config): RpcTransport {
payload,
signal,
}: Parameters<RpcTransport>[0]): Promise<RpcResponse<TResponse>> {
const body = JSON.stringify(payload);
const body = toJson ? toJson(payload) : JSON.stringify(payload);
const requestInfo = {
...dispatcherConfig,
body,
Expand All @@ -66,6 +68,9 @@ export function createHttpTransport(config: Config): RpcTransport {
statusCode: response.status,
});
}
if (fromJson) {
return fromJson(await response.text(), payload) as TResponse;
}
return await response.json();
};
}

0 comments on commit ea59901

Please sign in to comment.