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

Add third parameter with response to trace and allow it to be asynchronous #53

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,11 @@ await enhancedFetch("https://example.com/api/users/:role", {
// method: 'POST',
// body: '{"some":{"object":{"as":{"body":{}}}}}',
// }
// Response {}
```

The `trace` function can also return a `Promise<void>` in order to send traces to an external service or database.

## typedResponse

A type-safe wrapper around the `Response` object. It adds a `json` and `text` method that will parse the response with a given zod schema. If you don't provide a schema, it will return `unknown` instead of `any`, then you can also give it a generic to type cast the result.
Expand Down
2 changes: 2 additions & 0 deletions src/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ describe('enhancedFetch', () => {
method: 'POST',
body: `{"id":1,"name":{"first":"John","last":"Doe"}}`,
},
expect.any(Response),
)
})

Expand Down Expand Up @@ -358,6 +359,7 @@ describe('makeFetcher', () => {
body: `{"id":1,"name":{"first":"John","last":"Doe"}}`,
headers: new Headers(),
},
expect.any(Response),
)
})
})
Expand Down
6 changes: 3 additions & 3 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function typedResponse(
* @param requestInit the requestInit to be passed to the fetch request. It is the same as the `RequestInit` type, but it also accepts a JSON-like `body` and an object-like `query` parameter.
* @param requestInit.body the body of the request. It will be automatically stringified so you can send a JSON-like object
* @param requestInit.query the query parameters to be added to the URL
* @param requestInit.trace a function that receives the URL and the requestInit and can be used to log the request
* @param requestInit.trace a function that receives the URL, the requestInit and a clone of the response in order to log or troubleshoot the request
* @returns a Response with typed json and text methods
* @example const response = await fetch("https://example.com/api/users");
* const users = await response.json(userSchema);
Expand All @@ -83,11 +83,11 @@ async function enhancedFetch<T extends string | URL>(
const body = ensureStringBody(reqInit.body)
const withParams = replaceURLParams<T>(url, reqInit.params ?? ({} as never))
const fullURL = addQueryToURL(withParams, query)

const enhancedReqInit = { ...reqInit, body }
trace?.(fullURL, enhancedReqInit)

const response = await fetch(fullURL, enhancedReqInit)

await trace?.(fullURL, enhancedReqInit, typedResponse(response.clone()))
return typedResponse(response)
}

Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ type EnhancedRequestInit<T = string> = Omit<RequestInit, 'body' | 'method'> & {
body?: JSONValue | BodyInit | null
query?: SearchParams
params?: PathParams<T>
trace?: (...args: Parameters<typeof fetch>) => void
trace?: (
fullUrl: string | URL,
init: EnhancedRequestInit,
response: TypedResponse,
) => void | Promise<void>
}

type ServiceRequestInit<T = string> = Omit<EnhancedRequestInit<T>, 'method'>
Expand Down
Loading