diff --git a/.prettierrc.json b/.prettierrc.json
deleted file mode 100644
index 18edf11..0000000
--- a/.prettierrc.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "arrowParens": "avoid",
- "bracketSpacing": true,
- "bracketSameLine": false,
- "jsxSingleQuote": true,
- "printWidth": 100,
- "semi": true,
- "singleQuote": true,
- "tabWidth": 2,
- "trailingComma": "all"
-}
diff --git a/README.md b/README.md
index 59cca7d..b1f5014 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Fetch tools
-Set of utilities for JS [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) function.
+Set of utilities for JS
+[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) function.
## Goals
@@ -26,21 +27,19 @@ bun add @krutoo/fetch-tools
Creating fetch with some extra features.
```ts
-import { configureFetch, applyMiddleware } from '@krutoo/fetch-tools';
-import { validateStatus, defaultHeaders, log } from '@krutoo/fetch-tools/middleware';
+import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
+import { defaultHeaders, log, validateStatus } from '@krutoo/fetch-tools/middleware';
// configure your own fetch...
const myFetch = configureFetch(
fetch,
applyMiddleware(
// validate status (like in axios)
- validateStatus(status => status >= 200 && status < 300),
-
+ validateStatus((status) => status >= 200 && status < 300),
// add default headers
defaultHeaders({
'user-agent': 'test',
}),
-
// log request stages (before request, after response, on catch)
log({
onCatch: ({ error }) => console.error(error),
@@ -50,8 +49,8 @@ const myFetch = configureFetch(
// ...and using it like normal fetch
myFetch('posts/1')
- .then(res => res.json())
- .then(data => console.log(data));
+ .then((res) => res.json())
+ .then((data) => console.log(data));
```
## Middleware
@@ -83,14 +82,14 @@ async function myMiddleware(request, next) {
Returns a middleware that will validate status.
```ts
-import { configureFetch, applyMiddleware } from '@krutoo/fetch-tools';
+import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { validateStatus } from '@krutoo/fetch-tools/middleware';
const myFetch = configureFetch(
fetch,
applyMiddleware(
// fetch promise will be rejected when status is not valid
- validateStatus(status => status >= 200 && status < 300),
+ validateStatus((status) => status >= 200 && status < 300),
),
);
```
@@ -100,7 +99,7 @@ const myFetch = configureFetch(
Returns a middleware that will set default headers to request.
```ts
-import { configureFetch, applyMiddleware } from '@krutoo/fetch-tools';
+import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { defaultHeaders } from '@krutoo/fetch-tools/middleware';
const myFetch = configureFetch(
@@ -117,7 +116,7 @@ const myFetch = configureFetch(
Returns a middleware that will log phases by handler.
```ts
-import { configureFetch, applyMiddleware } from '@krutoo/fetch-tools';
+import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { log } from '@krutoo/fetch-tools/middleware';
const myFetch = configureFetch(
@@ -160,7 +159,7 @@ const enhance = applyMiddleware(
);
Deno.serve(
- enhance(req => {
+ enhance((req) => {
return new Response('
Main page
');
}),
);
@@ -212,7 +211,8 @@ Bun.serve({
Currently there is no builtin server implementation based on Fetch API in Node.js.
-It is possible to use _adapter_ for `node:http` or `express` from [@whatwg-node/server](https://www.npmjs.com/package/@whatwg-node/server).
+It is possible to use _adapter_ for `node:http` or `express` from
+[@whatwg-node/server](https://www.npmjs.com/package/@whatwg-node/server).
```ts
import { router } from '@krutoo/fetch-tools';
@@ -237,7 +237,7 @@ server.listen(8080);
You can use middleware for server handlers too:
```ts
-import { router, applyMiddleware } from '@krutoo/fetch-tools';
+import { applyMiddleware, router } from '@krutoo/fetch-tools';
import { log } from '@krutoo/fetch-tools/middleware';
const enhance = applyMiddleware(
@@ -266,13 +266,17 @@ Cookies can be used in different ways on the server.
### Browser like behavior
-If you want to imitate browser behavior as much as possible in terms of working with cookies, you can use `@krutoo/fetch-tools` together with `fetch-cookie`.
+If you want to imitate browser behavior as much as possible in terms of working with cookies, you
+can use `@krutoo/fetch-tools` together with `fetch-cookie`.
-To use **fetch-cookie** as an middleware, follow [these](https://github.com/valeriangalliat/fetch-cookie/issues/79#issuecomment-1672188226) instructions.
+To use **fetch-cookie** as an middleware, follow
+[these](https://github.com/valeriangalliat/fetch-cookie/issues/79#issuecomment-1672188226)
+instructions.
### Microfrontends
-Server part of the microfrontend can make requests to some HTTP API on behalf of the user, sending his cookies in requests.
+Server part of the microfrontend can make requests to some HTTP API on behalf of the user, sending
+his cookies in requests.
In this case you can use just `defaultHeaders` middleware:
diff --git a/deno.json b/deno.json
index d99b3d2..efc1274 100644
--- a/deno.json
+++ b/deno.json
@@ -2,7 +2,7 @@
"name": "@krutoo/fetch-tools",
"version": "0.0.0",
"tasks": {
- "lint": "deno lint && deno check src/**/*.ts",
+ "lint": "deno check src/**/*.ts && deno lint && deno fmt --check",
"build-npm": "deno run -A scripts/build-npm.ts"
},
"imports": {
@@ -21,7 +21,7 @@
"indentWidth": 2,
"semiColons": true,
"singleQuote": true,
- "exclude": ["npm/**/*", "example/**/*"]
+ "exclude": ["npm/**/*"]
},
"lint": {
"exclude": ["npm/**/*"]
diff --git a/src/configure.ts b/src/configure.ts
index 13a51ba..dc1c7f4 100644
--- a/src/configure.ts
+++ b/src/configure.ts
@@ -1,4 +1,4 @@
-import type { Handler, Enhancer, Middleware } from './types.ts';
+import type { Enhancer, Handler, Middleware } from './types.ts';
/**
* Enhance fetch function by provided enhancer.
@@ -12,7 +12,7 @@ export function configureFetch(
fetchFn: T,
enhance?: Enhancer,
): typeof fetch {
- let inner: Handler = request => fetchFn(request);
+ let inner: Handler = (request) => fetchFn(request);
if (enhance) {
inner = enhance(inner);
@@ -28,15 +28,15 @@ export function configureFetch(
*/
export function applyMiddleware(...list: Array): Enhancer {
if (list.length === 0) {
- return handler => handler;
+ return (handler) => handler;
}
- return handler => {
+ return (handler) => {
let result = handler;
for (const item of list.reverse()) {
const next = result;
- result = request => Promise.resolve(item(request, next));
+ result = (request) => Promise.resolve(item(request, next));
}
return result;
diff --git a/src/middleware/default-headers.ts b/src/middleware/default-headers.ts
index df40f5d..0b733e6 100644
--- a/src/middleware/default-headers.ts
+++ b/src/middleware/default-headers.ts
@@ -1,18 +1,31 @@
import type { Middleware } from '../types.ts';
+/** Options of default headers middleware. */
+export interface DefaultHeadersOptions {
+ /**
+ * How to add header to request headers.
+ * - "set" - headers will be added using "set" method
+ * - "append" - headers will be added using "append" method
+ */
+ strategy?: 'set' | 'append';
+}
+
/**
* Returns a middleware that will set default headers to request.
* @param defaults Default headers.
* @return Middleware.
*/
-export function defaultHeaders(defaults: HeadersInit): Middleware {
+export function defaultHeaders(
+ defaults: HeadersInit,
+ { strategy = 'append' }: DefaultHeadersOptions = {},
+): Middleware {
return (request, next) => {
// IMPORTANT: for avoid mutate request, just create new Headers and Request here
const headers = new Headers(defaults);
if (request.headers) {
new Headers(request.headers).forEach((value, key) => {
- headers.append(key, value);
+ headers[strategy](key, value);
});
}
diff --git a/src/middleware/jwt.ts b/src/middleware/jwt.ts
new file mode 100644
index 0000000..0711bb7
--- /dev/null
+++ b/src/middleware/jwt.ts
@@ -0,0 +1,35 @@
+import type { Middleware } from '../types.ts';
+
+/** Options of JWT middleware. */
+export interface JwtMiddlewareOptions {
+ /** JWT Token. */
+ token: string | (() => string | Promise);
+
+ /** Filter. Takes request, should return boolean. When returns false, JWT payload will not be added to request. */
+ filter?: (request: Request) => boolean;
+}
+
+/**
+ * Simple JWT middleware. Will add "Authorization" header with JWT token to request.
+ * @param options Options.
+ * @returns Middleware.
+ */
+export function jwt({
+ token,
+ filter = () => true,
+}: JwtMiddlewareOptions): Middleware {
+ const getToken = typeof token === 'function' ? token : () => token;
+
+ return async (request, next) => {
+ if (!filter(request)) {
+ return next(request);
+ }
+
+ // IMPORTANT: for avoid mutate request, just create new Headers and Request here
+ const headers = new Headers(request.headers);
+
+ headers.set('Authorization', `Bearer ${await getToken()}`);
+
+ return next(new Request(request, { headers }));
+ };
+}
diff --git a/src/middleware/mod.ts b/src/middleware/mod.ts
index 10cc4df..35445b9 100644
--- a/src/middleware/mod.ts
+++ b/src/middleware/mod.ts
@@ -1,12 +1,18 @@
-export { defaultHeaders } from './default-headers.ts';
+export { defaultHeaders, type DefaultHeadersOptions } from './default-headers.ts';
+
export {
- log,
- type LogData,
type DoneLogData,
type FailLogData,
+ log,
+ type LogData,
type LogHandler,
type LogHandlerFactory,
} from './log.ts';
+
export { retry } from './retry.ts';
+
export { validateStatus, type ValidateStatusOptions } from './validate-status.ts';
+
export { proxy, type ProxyOptions, type ProxyRequestFilter } from './proxy.ts';
+
+export { jwt, type JwtMiddlewareOptions } from './jwt.ts';
diff --git a/src/middleware/proxy.ts b/src/middleware/proxy.ts
index 6ed7e85..2afd4f8 100644
--- a/src/middleware/proxy.ts
+++ b/src/middleware/proxy.ts
@@ -19,7 +19,7 @@ export interface ProxyOptions {
* Simple proxy middleware for servers based on Web Fetch API.
* Based on good article: https://blog.r0b.io/post/creating-a-proxy-with-deno/
*/
-export function proxy({ filter, target, pathRewrite = p => p }: ProxyOptions): Middleware {
+export function proxy({ filter, target, pathRewrite = (p) => p }: ProxyOptions): Middleware {
const matches = createMatches(filter);
const createRequest = (url: URL, request: Request) => {
@@ -51,10 +51,10 @@ export function proxy({ filter, target, pathRewrite = p => p }: ProxyOptions): M
function createMatches(filter: ProxyOptions['filter']): ProxyRequestFilter {
switch (true) {
case Array.isArray(filter):
- return url => filter.some(item => url.pathname.startsWith(item));
+ return (url) => filter.some((item) => url.pathname.startsWith(item));
case typeof filter === 'string':
- return url => url.pathname.startsWith(filter);
+ return (url) => url.pathname.startsWith(filter);
case typeof filter === 'function':
return filter;
diff --git a/src/middleware/validate-status.ts b/src/middleware/validate-status.ts
index 3f04c57..2099fc7 100644
--- a/src/middleware/validate-status.ts
+++ b/src/middleware/validate-status.ts
@@ -18,7 +18,7 @@ export interface ValidateStatusOptions {
export function validateStatus(
validate: (status: number, request: Request, response: Response) => boolean,
{
- getThrowable = response => new Error(`Request failed with status ${response.status}`),
+ getThrowable = (response) => new Error(`Request failed with status ${response.status}`),
needDump = true,
}: ValidateStatusOptions = {},
): Middleware {
diff --git a/src/mod.ts b/src/mod.ts
index 0106f04..1f4d8d0 100644
--- a/src/mod.ts
+++ b/src/mod.ts
@@ -1,5 +1,5 @@
-export type { Handler, Enhancer, Middleware } from './types.ts';
-export { configureFetch, applyMiddleware } from './configure.ts';
+export type { Enhancer, Handler, Middleware } from './types.ts';
+export { applyMiddleware, configureFetch } from './configure.ts';
export { html, json } from './response.ts';
-export { router, route } from './server.ts';
+export { route, router } from './server.ts';
export { dump } from './utils/dump.ts';