Skip to content

Commit

Permalink
feat(fetch): include status code in fetch client response (#1470)
Browse files Browse the repository at this point in the history
* feat(fetch): include http status code in `fetch` response

* chore: rerun `orval` in next sample app

* chore: update return object in custom fetch function

* chore: display http status code in next sample app
  • Loading branch information
soartec-lab authored Jun 20, 2024
1 parent d5592b6 commit 9404af4
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
20 changes: 17 additions & 3 deletions packages/fetch/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ ${
return \`${route}${queryParams ? '?${normalizedParams.toString()}' : ''}\`
}\n`;

const responseTypeName = `${operationName}Response`;
const responseTypeImplementation = `export type ${operationName}Response = {
data: ${response.definition.success || 'unknown'};
status: number;
}`;

const getUrlFnProperties = props
.filter(
(prop) =>
Expand All @@ -79,7 +86,7 @@ ${
.join(',');

const args = `${toObjectString(props, 'implementation')} ${isRequestOptions ? `options?: RequestInit` : ''}`;
const retrunType = `Promise<${response.definition.success || 'unknown'}>`;
const retrunType = `Promise<${responseTypeName}>`;

const globalFetchOptions = isObject(override?.requestOptions)
? `${stringify(override?.requestOptions)?.slice(1, -1)?.trim()}`
Expand All @@ -102,7 +109,12 @@ ${
${fetchBodyOption}
}
`;
const fetchResponseImplementation = `const res = await fetch(${fetchFnOptions})\n\nreturn res.json()`;
const fetchResponseImplementation = `const res = await fetch(${fetchFnOptions}
)
const data = await res.json()
return { status: res.status, data }
`;
const customFetchResponseImplementation = `return ${mutator?.name}<${retrunType}>(${fetchFnOptions});`;

const bodyForm = generateFormDataAndUrlEncodedFunction({
Expand All @@ -120,7 +132,9 @@ ${
const fetchImplementation = `export const ${operationName} = async (${args}): ${retrunType} => {\n${fetchImplementationBody}}`;

const implementation =
`${getUrlFnImplementation}\n` + `${fetchImplementation}\n`;
`${responseTypeImplementation}\n\n` +
`${getUrlFnImplementation}\n` +
`${fetchImplementation}\n`;

return implementation;
};
Expand Down
36 changes: 28 additions & 8 deletions samples/next-app-with-fetch/app/gen/pets/pets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ type NonReadonly<T> = [T] extends [UnionToIntersection<T>]
/**
* @summary List all pets
*/
export type listPetsResponse = {
data: Pets;
status: number;
};

export const getListPetsUrl = (params?: ListPetsParams) => {
const normalizedParams = new URLSearchParams();

Expand All @@ -60,8 +65,8 @@ export const getListPetsUrl = (params?: ListPetsParams) => {
export const listPets = async (
params?: ListPetsParams,
options?: RequestInit,
): Promise<Pets> => {
return customFetch<Promise<Pets>>(getListPetsUrl(params), {
): Promise<listPetsResponse> => {
return customFetch<Promise<listPetsResponse>>(getListPetsUrl(params), {
...options,
method: 'GET',
});
Expand All @@ -70,15 +75,20 @@ export const listPets = async (
/**
* @summary Create a pet
*/
export type createPetsResponse = {
data: Pet;
status: number;
};

export const getCreatePetsUrl = () => {
return `http://localhost:3000/pets`;
};

export const createPets = async (
createPetsBodyItem: CreatePetsBodyItem[],
options?: RequestInit,
): Promise<Pet> => {
return customFetch<Promise<Pet>>(getCreatePetsUrl(), {
): Promise<createPetsResponse> => {
return customFetch<Promise<createPetsResponse>>(getCreatePetsUrl(), {
...options,
method: 'POST',
body: JSON.stringify(createPetsBodyItem),
Expand All @@ -88,15 +98,20 @@ export const createPets = async (
/**
* @summary Update a pet
*/
export type updatePetsResponse = {
data: Pet;
status: number;
};

export const getUpdatePetsUrl = () => {
return `http://localhost:3000/pets`;
};

export const updatePets = async (
pet: NonReadonly<Pet>,
options?: RequestInit,
): Promise<Pet> => {
return customFetch<Promise<Pet>>(getUpdatePetsUrl(), {
): Promise<updatePetsResponse> => {
return customFetch<Promise<updatePetsResponse>>(getUpdatePetsUrl(), {
...options,
method: 'PUT',
body: JSON.stringify(pet),
Expand All @@ -106,15 +121,20 @@ export const updatePets = async (
/**
* @summary Info for a specific pet
*/
export type showPetByIdResponse = {
data: Pet;
status: number;
};

export const getShowPetByIdUrl = (petId: string) => {
return `http://localhost:3000/pets/${petId}`;
};

export const showPetById = async (
petId: string,
options?: RequestInit,
): Promise<Pet> => {
return customFetch<Promise<Pet>>(getShowPetByIdUrl(petId), {
): Promise<showPetByIdResponse> => {
return customFetch<Promise<showPetByIdResponse>>(getShowPetByIdUrl(petId), {
...options,
method: 'GET',
});
Expand Down
5 changes: 4 additions & 1 deletion samples/next-app-with-fetch/app/pets.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { listPets } from './gen/pets/pets';

export default async function Pets() {
const pets = await listPets();
const { data: pets, status } = await listPets();

return (
<div>
<h1 className="text-4xl">Pets by server actions</h1>

<ul>
{pets.map((pet) => (
<li key={pet.id}>{pet.name}</li>
))}
</ul>

<h2 className="text-xl">Status: {status}</h2>
</div>
);
}
2 changes: 1 addition & 1 deletion samples/next-app-with-fetch/custom-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ export const customFetch = async <T>(
const response = await fetch(request);
const data = await getBody<T>(response);

return data;
return { status: response.status, data } as T;
};

0 comments on commit 9404af4

Please sign in to comment.