Solid-Fetch
SolidFetch is created with one goal in mind, to make client-server-requests as easy as possible. These means: less code, less headache and more power over the communication channel.
Core tools
Supporting injectable request properties in url, parameters, search-query, headers and body. Supporting intercepting requests, responses and errors to easily control and maintain communication with servers.
Install
yarn add solid-fetch
or:
npm install solid-fetch
Usage
Since node v18 fetch
is supported with no extra effort so the native fetch
function will be used on both browser and node.
import SolidFetch from 'solid-fetch'
const SolidFetchClient = new SolidFetch()
SolidFetchClient.request`http://test-server.io/messages`()
.then((res) => {
console.log('result from SolidFetch')
})
.catch((err) => {
console.log('error from SolidFetch')
})
Config Props
Prop | Type | Default | Description |
---|---|---|---|
initInjectables | Object |
{} | The props the api-client can inject into the request properties: url , headers , etc. |
globalHeaders | Object |
{} | Global headers to be injected to all requests |
globalQuery | Object |
{} | Global search-query params to be injected to all requests |
interceptedReq | Array |
[] | Array of interceptors to run before request is sent |
interceptedRes | Array |
[] | Array of interceptors to run after response is received |
interceptedErr | Array |
[] | Array of interceptors to run after error is received |
Set Injectables
SolidFetch comes very handy when you have plenty of dynamic props that needs to create the request. Using SolidFetch you can give the module pieces of data that you would like to use later, ex. access-token, language or user-id.
The example shows the injectables being set at one spot, but you can set them as many times as you want from where ever you need. Also by setting the two objects will be merged, only former existing fields will be overwritten.
import SolidFetch from 'solid-fetch'
const SolidFetchClient = new SolidFetch()
SolidFetchClient.setInjectables({
language: 'de',
userId: '123',
jwtToken: () => dataStore.getState().jwtToken
})
Consume Injections in Request
After setting the injectables you can just refer to it during the request construction since the module is already aware of it.
import SolidFetch from 'solid-fetch'
// Injection in URL
SolidFetch.request`http://test-server.io/${(p) => p.language}/messages`({
query: {
// Injection in search-query
language: (p) => p.language
}
headers: {
// Injection in headers
Authorization: (p) => `Bearer ${p.jwtToken}`
},
body: (p) => ({
// Injection in body
userId: p.userId
})
})
.then((res) => {
console.log('result from SolidFetch')
})
.catch((err) => {
console.log('error from SolidFetch')
})
Note: Body, Query, Headers can be resolved in two ways
- Less intuitive but fits for object with nested keys:
SolidFetch.request`url`({
body: (p) => ({
// Injection in body
userId: p.userId
})
})
- Similar to the other injections but works only with first level keys:
SolidFetch.request`url`({
body: {
// Injection in body
userId: (p) => p.userId
}
})
Typescript Support
Types for the injectables are partially supported.
import SolidFetch from 'solid-fetch'
interface Injectables {
apiUrl
}
const SolidFetchClient = new SolidFetch<Injectables>()
SolidFetchClient.request`${(p) => p.apiUrl}/messages`()
.then((res) => {
console.log('result from SolidFetch')
})
.catch((err) => {
console.log('error from SolidFetch')
})
* p
will be correctly typed and will offer apiUrl
as auto complete
Global Injections
Same like injectables per a request, you can set to all requests globally added values on headers and search-query. They will be added to the request without further code. The header or search-query can be overwritten per specific request by giving the prop with a different value.
import SolidFetch from 'solid-fetch'
SolidFetch.setConfig({
globalHeaders: {
Authorization: (p) => `Bearer ${p.jwtToken}`
}
})
SolidFetch.request`http://test-server.io/${p => p.language}/messages`({
query: {
language: p => p.language
}
// No need to set Authorization header since it will be added to all requests
})
.then((res) => {
console.log('result from SolidFetch')
})
.catch((err) => {
console.log('error from SolidFetch')
})
Using with Typescript (Injectables & Response)
Typescript is supported as well. Injectables can be typed to have autocompletion. Requests can receive a type to have typed response. Note the type will be present on the data
prop of the response.
import SolidFetch from 'solid-fetch'
interface Injectables {
baseUrl: string
userId: string
jwtToken: () => string
}
const SolidFetchClient = new SolidFetch<Injectables>({
initInjectables: {
baseUrl: 'http://test-server.io',
userId: '123',
jwtToken: () => dataStore.getState().jwtToken
}
})
const res = await SolidFetchClient.request<string>`${p => p.baseUrl}/messages`()
Interceptions
SolidFetch gives the ability to intercept all outgoing and incoming communication. That can be useful for error logging, caching, usage-statistics, etc.
Interceptor is an object which must have an action
property, it is recommended to add name
or any other
identifier to the interceptor for further references. Interceptor action
can mutate the current value of the action or just to cause side-effects.
Since you might want to run more than one interception, interceptions are stored in arrays and will be executed in sequence. If nothing returned from the interceptor, the next interceptor will run on the last generated value. The interceptors are reduce functions that will in the end have a similar structure to the data needed.
Request Interception
import SolidFetch from 'solid-fetch'
SolidFetch.setConfig({
interceptedReq: [{
name: 'debugging',
action: (request) => {
console.log('caught a request')
console.log({ request })
},
}],
})
Response Interception
Response interceptors will get the result of the request after processing. Means, only if it has
status of 200, also if it is application/json
then the parsed json will be given, otherwise just
the raw response value.
import SolidFetch from 'solid-fetch'
SolidFetch.setConfig({
interceptedRes: [{
name: 'debugging',
action: (result) => {
console.log('caught a response')
statisticService.post(result)
},
}],
})
Error Interception
Error interceptors will get the error data of the request.
import SolidFetch from 'solid-fetch'
SolidFetch.setConfig({
interceptedErr: [{
name: 'error-tracer',
action: (error) => {
console.log('caught a response')
errorTracer.postError(error)
},
}],
})
*If the status code is NOT 200-299, an error will be thrown.
Request, Response, Error Shape
Request:
{
url: String,
requestOptions: {
method: String = 'GET',
headers: Object = {},
query: Object = {},
body: String,
}
}
Response:
{
data: <ParsedResult> || <RawResponse>,
headers: Object,
ok: Boolean,
redirected: Boolean,
size: Number,
status: Number,
statusText: String,
request: {
url: String,
requestOptions: {
method: String = 'GET',
headers: Object = {},
query: Object = {},
body: String,
}
}
}
Standard JS Error with JSON content:
{
name: String,
description: String,
response: <RawResponse>, // optional
request: {
url: String,
requestOptions: {
method: String = 'GET',
headers: Object = {},
query: Object = {},
body: String,
}
}
}
Advanced
Use your solid-fetch configs outside of it
import SolidFetchClient from './your-solid-fetch-client'
const { useId, jwtToken } = SolidFetchClient.getInjectables()