Skip to content

Commit

Permalink
fix(client): fix request error handler (#756)
Browse files Browse the repository at this point in the history
  • Loading branch information
gao-sun authored Jul 2, 2024
1 parent e0b03ca commit e0cc59f
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 31 deletions.
7 changes: 7 additions & 0 deletions .changeset/short-moose-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@logto/client": patch
---

fix request error handler

Clone the response object before consuming it to avoid the unexpected "Body has already been consumed." error.
53 changes: 23 additions & 30 deletions packages/client/src/utils/requester.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,28 @@ describe('createRequester', () => {
const message = 'some error message';

test('failing response json with code and message should throw LogtoRequestError with same code and message', async () => {
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => ({ code, message }),
clone: () => ({}),
});
const fetchFunction = vi
.fn()
.mockResolvedValue(new Response(JSON.stringify({ code, message }), { status: 400 }));
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toMatchObject(new LogtoRequestError(code, message));
});

test('failing response json with more than code and message should throw LogtoRequestError with same code and message', async () => {
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => ({ code, message, foo: 'bar' }),
clone: () => ({}),
});
const fetchFunction = vi
.fn()
.mockResolvedValue(
new Response(JSON.stringify({ code, message, foo: 'bar' }), { status: 400 })
);
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toMatchObject(new LogtoRequestError(code, message));
});

test('failing response json with only code should throw LogtoError', async () => {
const json = { code };
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => json,
});
const fetchFunction = vi
.fn()
.mockResolvedValue(new Response(JSON.stringify(json), { status: 400 }));
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toMatchObject(
new LogtoError('unexpected_response_error', json)
Expand All @@ -53,10 +50,9 @@ describe('createRequester', () => {

test('failing response json with only message should throw LogtoError', async () => {
const json = { message };
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => json,
});
const fetchFunction = vi
.fn()
.mockResolvedValue(new Response(JSON.stringify(json), { status: 400 }));
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toMatchObject(
new LogtoError('unexpected_response_error', json)
Expand All @@ -65,26 +61,23 @@ describe('createRequester', () => {

test('failing response json without code and message should throw LogtoError', async () => {
const json = {};
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => json,
});
const fetchFunction = vi
.fn()
.mockResolvedValue(new Response(JSON.stringify(json), { status: 400 }));
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toMatchObject(
new LogtoError('unexpected_response_error', json)
);
});

test('failing response with non-json text should throw TypeError', async () => {
const fetchFunction = vi.fn().mockResolvedValue({
ok: false,
json: async () => {
throw new TypeError('not json content');
},
clone: () => ({}),
});
const fetchFunction = vi.fn().mockResolvedValue(
new Response('not json content', {
status: 400,
})
);
const requester = createRequester(fetchFunction);
await expect(requester('foo')).rejects.toThrowError(TypeError);
await expect(requester('foo')).rejects.toThrowError(SyntaxError);
});
});
});
3 changes: 2 additions & 1 deletion packages/client/src/utils/requester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const createRequester = (fetchFunction: typeof fetch): Requester => {
const response = await fetchFunction(...args);

if (!response.ok) {
const cloned = response.clone();
const responseJson = await response.json();
console.error(`Logto requester error: [status=${response.status}]`, responseJson);

Expand All @@ -22,7 +23,7 @@ export const createRequester = (fetchFunction: typeof fetch): Requester => {

// Expected request error from server
const { code, message } = responseJson;
throw new LogtoRequestError(code, message, response.clone());
throw new LogtoRequestError(code, message, cloned);
}

return response.json();
Expand Down

0 comments on commit e0cc59f

Please sign in to comment.