My new Nuxt module for doing amazing things.
- ⛰ Foo
- 🚠 Bar
- 🌲 Baz
- Add
nuxt-strict-fetch
dependency to your project
# Using pnpm
pnpm add -D nuxt-strict-fetch
# Using yarn
yarn add --dev nuxt-strict-fetch
# Using npm
npm install --save-dev nuxt-strict-fetch
- Add
nuxt-strict-fetch
to themodules
section ofnuxt.config.ts
export default defineNuxtConfig({
modules: [
'nuxt-strict-fetch'
]
})
That's it! You can now use Nuxt Strict Fetch in your Nuxt app ✨
export default defineNuxtConfig({
modules: [
'nuxt-strict-fetch'
],
strictFetch: {
// base URL for all requests
baseURL: '/api/',
},
})
If you wish to define some global options for all requests in plugin, you can use the StrictFetch.init
:
export default defineNuxtPlugin(() => {
const { $csrfFetch } = useNuxtApp(); // nuxt-csurf module $csrfFetch for example
StrictFetch.init({
onRequest(context) {
context.options.headers = {
...context.options.headers,
Custom: 'Value',
};
},
fetch: $csrfFetch, // option for default Nuxt $fetch reassignment
});
});
Nuxt Strict Fetch module assumes the following method declaration:
// ~/api/common.ts for example
type Filter = { name?: string };
type Item = { id: number; name: string; };
type List = { items: Item[] };
type CreateItem = { name: string; };
const CommonAPI = {
list: StrictFetch.prepare<List, null, null, Filter>({
url: 'list',
}),
create: StrictFetch.prepare<Item, CreateItem>({
url: 'list',
method: HTTPMethod.post,
}),
details: StrictFetch.prepare<Item, null, { id: number }>({
url: ({ id }) => `list/${id}`,
}),
}
prepare
method has the following generic types:
StrictFetch.prepare<R /* response body */, B /* common body */, P /* common params */, Q /* common query */>
Also, you may define API with validation schemas:
// ~/api/common.ts for example
import * as yup from 'yup';
const filterSchema = yup.object().shape({ name: yup.string() });
const itemSchema = yup.object().required().shape({
id: yup.string().required(),
name: yup.string().required(),
});
const listSchema = yup.array().required().of(itemSchema);
const createItemBodySchema = yup.object().required().shape({
name: yup.string().required(),
});
const detailsParamsSchema = yup.object().required().shape({
id: yup.number().required(),
});
const CommonAPI = {
list: StrictFetch.prepare({
url: 'list',
schemas: { response: listSchema, query: filterSchema },
}),
create: StrictFetch.prepare({
url: 'list',
method: HTTPMethod.post,
schemas: { response: itemSchema, body: createItemBodySchema },
}),
details: StrictFetch.prepare({
url: ({ id }) => `list/${id}`,
schemas: { response: itemSchema, params: detailsParamsSchema },
}),
}
The second way also provide useRequest
composable validation feature.
Module provides the following composable methods:
-
useRequest
- method for using API method validation, state and TypeScript supporting for data.
const name = ref('');
const {
execute, // execute common after validation (execution will return undefined if validation failed or loading is processed)
parameters, // reactive data provided to second useRequest argument
isValid, // reactive variable for validation result
isLoading, // reactive variable for loading state
} = useRequest(
CommonAPI.create,
() => ({
body: { name: name.value },
}),
{
validation: () => false, // additional validation that will be included in isValid variable
},
);
const onSubmit = () => {
execute()?.then( /* ... */ ).catch( /* ... */ );
};
Nuxt Strict Fetch module provides the opportunity to subscribe to API events:
StrictFetch.hooks.subscribe('method:create:start', () => { /* ... */ });
StrictFetch.hooks.subscribe('method:create:finish', () => { /* ... */ });
StrictFetch.hooks.unsubscribe('method:create:start', () => { /* ... */ });
StrictFetch.hooks.unsubscribe('method:create:finish', () => { /* ... */ });
// where `create` is methodKey field of the method
You can to create order of requests. When orderKey: 'my-order'
key is added to methods, its will be executed only one by one.
In other words, when second request with orderKey: 'my-order'
will be executed, request will be sent only after first finish.
const OrderAPI = {
first: StrictFetch.prepare({
url: 'first',
orderKey: 'my-order',
}),
second: StrictFetch.prepare({
url: 'second',
orderKey: 'my-order',
}),
};
OrderAPI.first();
OrderAPI.second(); // will wait for first common finish
const options = {
selfInterrupted: true, // will interrupt previous requests when new common will be executed
onError: () => { /* ... */ }, // will be called on error but ignored 'AbortError' error
methodKey: 'my-method', // key of method for subscribing
orderKey: 'my-order', // key of order for subscribing or ordering requests
proxyServerCookies: true, // will send cookies from browser for common on server side
};
/** global options injected in StrictFetch */
StrictFetch.init(options);
// or
/** options for current common */
StrictFetch.prepare({
url: 'url',
...options,
})
Nuxt Strict Fetch have three ways to work with FormData:
const FormDataAPI = {
first: StrictFetch.prepare<null, FormData>({
url: 'form-data-url',
method: HTTPMethod.post,
}),
second: StrictFetch.prepare<null, { name: string; file: File; tags: string[] }>({
url: 'form-data-url',
method: HTTPMethod.post,
// will be converted to FormData automatically
// `name` and `file` as is
// `tags` as array of FormData fields with the same key
formData: true,
})
};
// in plugin
// global declaration to use FormData common body
StrictFetch.init({ formData: true });
// in methods file
const CommonAPI = {
formDataMethod: StrictFetch.prepare<null, { name: string; file: File; tags: string[] }>({
url: 'form-data-url',
method: HTTPMethod.post,
}),
jsonDataMethod: StrictFetch.prepare<null, { name: string; tags: string[] }>({
url: 'json-data-url',
method: HTTPMethod.post,
formData: false, // disabling for current method
}),
};
If you wish to define some logic for catching request, you might do it in options:
StrictFetch.init({
onRequest(context) {
const expiredAt = localStorage.getItem('token')
if (expiredAt) context.options.headers = { 'x-token': expiredAt }
},
catch(error) {
if (error.context.response.status === 401) {
const expiredAt = new Date()
expiredAt.setSeconds(expiredAt.getSeconds() + 5)
localStorage.setItem('token', expiredAt.toISOString())
// Request repeating for example
return $fetch(error.context.request, error.context.options);
}
throw error
},
})
You can import types from nuxt-strict-fetch/types
path.
import type { StrictFetchOptions } from 'nuxt-strict-fetch/types';
# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# Develop with the playground
npm run dev
# Build the playground
npm run dev:build
# Run ESLint
npm run lint
# Run Vitest
npm run test
npm run test:watch
# Release new version
npm run release