Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve 204 support #24

Merged
merged 15 commits into from
Jul 8, 2024
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,30 @@ const responseBody = await sendPost(client, {
})
```

CarlosGamero marked this conversation as resolved.
Show resolved Hide resolved
### No content response handling (HTTP 204)

SDK methods has a parameter (`isEmptyResponseExpected`) to specify if 204 response should be treated as an error or not. By default it is treated as
valid except on `sendGet` method where it is treated as an error. Usage example:

```ts
const response = await sendGet(client, {
path: '/',
isEmptyResponseExpected: true,
})
```

### Non json response handling
CarlosGamero marked this conversation as resolved.
Show resolved Hide resolved

SDK methods has a parameter (`isNonJSONResponseExpected`) to specify if non json responses should be treated as an error
or not. By default it is treated as valid except on `sendGet` method where it is treated as an error. Usage example:

```ts
const response = await sendGet(client, {
path: '/',
isNonJSONResponseExpected: true,
})
```

## Credits

This library is brought to you by a joint effort of Lokalise engineers:
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"@types/node": "^20.11.5",
"@typescript-eslint/eslint-plugin": "^7.0.1",
"@typescript-eslint/parser": "^7.0.1",
"@vitest/coverage-v8": "^1.2.2",
"@vitest/coverage-v8": "^1.6.0",
"jest-fail-on-console": "^3.1.2",
"eslint": "^8.56.0",
"eslint-plugin-import": "^2.29.1",
Expand All @@ -66,8 +66,8 @@
"prettier": "^3.2.5",
"rimraf": "^5.0.5",
"tsup": "8.1.0",
"typescript": "~5.5.2",
"vitest": "^1.2.2"
"typescript": "~5.5.3",
"vitest": "^1.6.0"
},
"keywords": [
"frontend",
Expand Down
223 changes: 220 additions & 3 deletions src/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable max-lines */
import failOnConsole from 'jest-fail-on-console'
import { getLocal } from 'mockttp'
import { expect } from 'vitest'
import wretch from 'wretch'
import { z } from 'zod'

Expand Down Expand Up @@ -50,13 +51,56 @@ describe('frontend-http-client', () => {
const responseBody = await sendPost(client, {
path: '/',
})

expect(responseBody).containSubset({
status: 204,
statusText: 'No Content',
})
})

it('returns unexpected no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPost('/').thenReply(204)

await expect(
sendPost(client, {
path: '/',
isEmptyResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected empty response.]`,
)
})

it('returns not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPost('/').thenReply(200)

const responseBody = await sendPost(client, {
path: '/',
})
expect(responseBody).containSubset({
status: 200,
statusText: 'OK',
})
})

it('returns unexpected not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPost('/').thenReply(200)

await expect(
sendPost(client, {
path: '/',
isNonJSONResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected non-JSON response.]`,
)
})

it('throws an error if response does not pass validation', async () => {
const client = wretch(mockServer.url)

Expand Down Expand Up @@ -302,13 +346,56 @@ describe('frontend-http-client', () => {
const responseBody = await sendPut(client, {
path: '/',
})

expect(responseBody).containSubset({
status: 204,
statusText: 'No Content',
})
})

it('returns unexpected no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPut('/').thenReply(204)

await expect(
sendPut(client, {
path: '/',
isEmptyResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected empty response.]`,
)
})

it('returns not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPut('/').thenReply(200)

const responseBody = await sendPut(client, {
path: '/',
})
expect(responseBody).containSubset({
status: 200,
statusText: 'OK',
})
})

it('returns unexpected not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPut('/').thenReply(200)

await expect(
sendPut(client, {
path: '/',
isNonJSONResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected non-JSON response.]`,
)
})

it('throws an error if response does not pass validation', async () => {
const client = wretch(mockServer.url)

Expand Down Expand Up @@ -484,6 +571,64 @@ describe('frontend-http-client', () => {
})
})

it('returns no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPatch('/').thenReply(204)

const responseBody = await sendPatch(client, {
path: '/',
})
expect(responseBody).containSubset({
status: 204,
statusText: 'No Content',
})
})

it('returns unexpected no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPatch('/').thenReply(204)

await expect(
sendPatch(client, {
path: '/',
isEmptyResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected empty response.]`,
)
})

it('returns not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPatch('/').thenReply(200)

const responseBody = await sendPatch(client, {
path: '/',
})
expect(responseBody).containSubset({
status: 200,
statusText: 'OK',
})
})

it('returns unexpected not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forPatch('/').thenReply(200)

await expect(
sendPatch(client, {
path: '/',
isNonJSONResponseExpected: false,
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Request to / has returned an unexpected non-JSON response.]`,
)
})

it('throws an error if response does not pass validation', async () => {
const client = wretch(mockServer.url)

Expand Down Expand Up @@ -659,6 +804,64 @@ describe('frontend-http-client', () => {
})
})

it('returns no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forGet('/').thenReply(204)

await expect(
sendGet(client, {
path: '/',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Request to / has returned an unexpected empty response."`,
)
})

it('returns expected no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forGet('/').thenReply(204)

const response = await sendGet(client, {
path: '/',
isEmptyResponseExpected: true,
})
expect(response).containSubset({
status: 204,
statusText: 'No Content',
})
})

it('returns not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forGet('/').thenReply(200)

await expect(
sendGet(client, {
path: '/',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Request to / has returned an unexpected non-JSON response."`,
)
})

it('returns expected not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forGet('/').thenReply(200)

const responseBody = await sendGet(client, {
path: '/',
isNonJSONResponseExpected: true,
})
expect(responseBody).containSubset({
status: 200,
statusText: 'OK',
})
})

it('throws an error if response does not pass validation', async () => {
const client = wretch(mockServer.url)

Expand Down Expand Up @@ -803,7 +1006,7 @@ describe('frontend-http-client', () => {
})

describe('sendDelete', () => {
it('returns a status if proceeded', async () => {
it('returns no content response', async () => {
const client = wretch(mockServer.url)

await mockServer.forDelete('/').thenReply(204)
Expand All @@ -814,5 +1017,19 @@ describe('frontend-http-client', () => {

expect(response).toMatchObject({ status: 204 })
})

it('returns not json response', async () => {
const client = wretch(mockServer.url)

await mockServer.forDelete('/').thenReply(200)

const responseBody = await sendDelete(client, {
path: '/',
})
expect(responseBody).containSubset({
status: 200,
statusText: 'OK',
})
})
})
})
Loading
Loading