Security News
pnpm 10.0.0 Blocks Lifecycle Scripts by Default
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
@airma/restful
Advanced tools
Provided a nice way to describe a restful http requests like:
import { client } from '@airma/restful';
const { rest } = client();
const root = rest('/path');
// GET http://host/path
root.get();
// GET http://host/path?param1=param1¶m2=param2
root.setParams({ param1:'param1', param2:'param2' }).get();
// GET http://host/path/child-path
root.path('child-path').get();
// GET http://host/path/child-path?param1=param1¶m2=param2
root.path('child-path').setParams({ param1:'param1', param2:'param2' }).get();
// POST http://host/path
// payload: {data:'data'}
root.setBody({data:'data'}).post();
// POST http://host/path/child-path
// payload: {data:'data'}
root.path('child-path').setBody({data:'data'}).post();
// POST http://host/path/child-path?param1=param1¶m2=param2
// payload: {data:'data'}
root.path('child-path').setParams({ param1:'param1', param2:'param2' }).setBody({data:'data'}).post();
With typescript
import { client, ResponseData } from '@airma/restful';
const { rest } = client();
const root = rest('/path');
type User = {
id: string;
name: string;
username: string;
}
async function getUser(id: string): Promise<User>{
try{
return root.setParams({ id }).get<User>();
} catch(e: any) {
console.log(e)
}
}
// if you need details from response, use `response` from `method promise`
async function getUserResponse(id: string): Promise<ResponseData<User>>{
try{
// with response
// when error { isError: true; error: any, networkError: boolean, status: number, headers?: Record<string, any> }
// when success { isError: false; data: User, status: number, headers: Record<string, any> }
return root.setParams({ id }).get<User>().response();
} catch(e: any) {
console.log(e)
}
}
The @airma/restful
contains a simple default config, it is not enough for you, you can config it:
import { client, ResponseData } from '@airma/restful';
const { rest } = client({
// request headers
headers: {...},
// default params ex { sessionId: 12 } -> http://host/path?sessionId=12&xx=...
defaultParams: {...},
// intercept the response data
responseInterceptor: ( data: ResponseData ) => {console.log(data)},
// you can replace the default request with your own request method
async request(url: string, requestConfig: RequestConfig){
return Promise<ResponseData>;
}
});
You can set a headers for the client, and the client always sends request with the headers you set.
client({
headers:{
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
......
}
})
You can set default params for the requests send by you client. These params always exist in the url
, unless you recover them with undefined in the specific request.
const {rest} = client({
defaultParams:{
sessionId: 12,
private:true
}
});
// http://host/path/child?sessionId=12&private=true&userId=1
rest('/path').path('child').setParams({userId:1}).get<User>();
// http://host/path/child?sessionId=12&userId=1
rest('/path').path('child').setParams({userId:1, private: undefined}).get<User>();
The default request sender is a window.fetch
adapter. If you want to replace it with some more good adapter, you can set request
.
The Request
is a callback, with a url and requestConfig as params, it should returns a promise with a ResponseData
type result.
type Request = (
// request url
url: string,
// requset config
requestConfig: RequestConfig
) => Promise<ResponseData>; // response data
The RequestConfig
type:
type ResponseType =
| 'json'
| 'text'
| 'formData'
| 'blob'
| 'arrayBuffer';
// the config you can set to `client`
type RestConfig = {
// just headers you set to client({headers:...})
headers?: Record<string, any>;
// the response data format: json, text, formData, blob, arrayBuffer
responseType?: ResponseType;
// just responseInterceptor you set to client({responseInterceptor})
responseInterceptor?: (
data: ResponseData
) => ResponseData | undefined;
// just defaultParams you set to client({defaultParams...})
defaultParams?: Record<string | number, any>;
// you can provide a param processor to stringify and parse
// params.
// type ParamsProcessor = {
// stringify(data:Record<string | number, any>): string,
// parse(data: string): Record<string | number, any>
// }
paramsProcessor?: () => ParamsProcessor;
/** the rest config you can refer to window.fetch API **/
credentials?: 'include' | 'omit' | 'same-origin';
cache?:
| 'default'
| 'force-cache'
| 'no-cache'
| 'no-store'
| 'only-if-cached'
| 'reload';
mode?: 'cors' | 'navigate' | 'no-cors' | 'same-origin';
redirect?: 'error' | 'follow' | 'manual';
integrity?: string;
keepalive?: boolean;
referrer?: string;
referrerPolicy?:
| ''
| 'no-referrer'
| 'no-referrer-when-downgrade'
| 'origin'
| 'origin-when-cross-origin'
| 'same-origin'
| 'strict-origin'
| 'strict-origin-when-cross-origin'
| 'unsafe-url';
window?: null;
}
type RequestConfig = RestConfig & {
// object style for ?param=xxx&more=xxx
params?: Record<string, any>;
// object style for post request payload
body?: Record<string, any>;
// GET, POST, PUT, DELETE
method?: Method;
};
The ResponseData
type:
export declare type SuccessResponse<T = any> = {
status: number;
headers?: Record<string, any>;
// the final promise result
data: T;
// is error request
isError: false;
};
export declare type ErrorResponse = {
status: number | null;
// error data
error: any;
// same value with `error`
data: any;
headers?: Record<string, any>;
// is network error
networkError: boolean;
// is error request
isError: true;
};
export declare type ResponseData<T = any> = SuccessResponse<T> | ErrorResponse;
You can replace request with the most popular request tool axios or other request API. And now you should know, that @airma/restful
just provides a restful style for you.
ResponseInterceptor
is a callback which helps you intercept a response. You can redefine if the request is an error request, and affect if the rest end should resolve or reject this result. You can also just make a log, and don't change result.
intercept response:
import {client, ResponseData} from '@airma/restful';
// for example we have to judge if the request is success
// by the `data.success`
const redefinition = (response:ResponseData) :ResponseData =>{
const {data, status, networkError} = response;
if ( data && data.success ) {
return {
data: data.data,
status,
isError: false
}
}else {
return {
error: data.data,
data: data.data,
status,
networkError,
isError: true
}
}
}
const { rest } = client({
responseInterceptor: redefinition
})
log response:
import {client, ResponseData} from '@airma/restful';
// the different with redefinition is we should return void,
// if we do not want to change result.
const log = (response:ResponseData): void =>{
const {data, status} = response;
console.log(status, data);
}
const { rest } = client({
responseInterceptor: log
})
If you want to keep the default request, but replace a better params processor like qs, you can use this setting.
import { client } from '@airma/restful';
import qs from 'qs';
export default client({
paramsProcessor(){
return {
stringify(data: Record<string | number, any>): string{
return qs.stringify(data);
},
parse(query: string): Record<string | number, any>{
return qs.parse(query);
}
}
}
})
Sometimes you want to change rest config when the client has been built. You can use config
method from client instance.
import {client} from '@airma/restful';
const {rest, config} = client();
async function test(){
// http://host/path?id=1
await rest('/path').setParams({id:1}).get();
// set a sessionId as a default param
config(
c => ({...c, defaultParams: {sessionId: 12} })
);
// http://host/path?sessionId=12&id=1
await rest('/path').setParams({id:1}).get();
}
You can set headers and other config too.
If you want to config a specific request, you should set config to a method.
rest('/path').get({headers:{...}, responseType:'text'});
As we have known, the method get
, post
, put
, delete
provides a promise which has a result we need directly. But, sometimes, we need a more original response data with status, headers, networkError properties. So, we can use response
from the method returns.
const res = await rest('/path').get<User>().response();
if(!res.isError){
return res.data; // User type
}
// we can get details now
const {error, networkError, headers} = res;
The response method is a parasitic method in the get
, post
, put
, delete
method returning promise. It returns a promise which result is a ResponseData
.
FAQs
A wrapper for asynchronous http requests with a restful style
The npm package @airma/restful receives a total of 14 weekly downloads. As such, @airma/restful popularity was classified as not popular.
We found that @airma/restful demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
Product
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Research
Security News
Socket researchers have discovered multiple malicious npm packages targeting Solana private keys, abusing Gmail to exfiltrate the data and drain Solana wallets.