@protorians/air-rest
Version:
api rest manager
321 lines (157 loc) • 5.11 kB
text/typescript
import type {
IAirRestServer,
IAirRestEndPoint,
IAirMethods,
IEndpointPayload,
IEndpointResponse
} from "./types";
export function stringifyPayload(payload: IEndpointPayload): string[] {
const out: string[] = [];
Object.entries(payload).forEach(({ 0: key, 1: value }) => {
if (typeof value == 'object') {
out[out.length] = (`${key}=${encodeURIComponent(JSON.stringify(value))}`);
}
else { out[out.length] = (`${key}=${encodeURIComponent(value)}`); }
});
return out
}
export function render<R extends IEndpointResponse>(
endpoint: RequestInfo,
options: RequestInit | undefined
) {
return new Promise<R>((done, fail) => {
fetch(endpoint, { ...options })
.then(r => r.json())
.then(data => done(data as R))
.catch(er => fail(er))
})
}
export function useEndpoint<P extends IEndpointPayload, R extends IEndpointResponse>() {
return new AirRestEndPoint<P, R>();
}
/**
* Création d'un point de chute
*/
export class AirRestEndPoint<P extends IEndpointPayload, R extends IEndpointResponse> implements IAirRestEndPoint<P, R>{
#rest: IAirRestServer | undefined = undefined;
#route: string | number = '';
#payload: P | FormData = {} as (P | FormData);
#method: IAirMethods = 'GET';
#transpilate: boolean = true;
get _route() { return this.#route; }
get _payload() { return this.#payload; }
get _method() { return this.#method; }
get _transpilate() { return this.#transpilate; }
/**
* Utilisation avec un serveur de points de chutes
* @param rest
*/
use(rest: IAirRestServer) {
this.#rest = rest;
return this;
}
method(method: IAirMethods) {
this.#method = method;
return this;
}
route(route: string | number) {
this.#route = route;
return this;
}
useForm(form: HTMLFormElement) {
const data = new FormData(form)
this.#transpilate = false;
this.#payload = data;
return this;
}
useFormData(formData: FormData) {
this.#transpilate = false;
this.#payload = formData;
return this;
}
slugs(...slugs: (string | number)[]) {
slugs.forEach((slug, key) => {
key++;
this.#route = this._route.toString().replace(new RegExp(`\\$${key}`, 'gi'), `${slug}`)
})
return this;
}
payload(payload: P) {
this.#payload = payload;
return this;
}
send(): Promise<R> | undefined {
switch (this._method) {
case 'POST': return this.#rest?.post<R>(this);
case 'PUT': return this.#rest?.put<R>(this);
case 'PATCH': return this.#rest?.patch<R>(this);
case 'DELETE': return this.#rest?.delete<R>(this);
default: return this.#rest?.get<R>(this);
}
}
}
export function transpilatePayload(payload?: object): BodyInit {
const formData = new FormData();
if (payload) {
Object.entries(payload).forEach(({ 0: name, 1: value }) =>
formData.append(name, value)
)
}
return formData;
}
export class AirRestServer implements IAirRestServer {
server: string;
options: RequestInit | undefined;
constructor(server: string, options: RequestInit | undefined) {
this.server = server;
this.options = options;
}
get<R extends IEndpointResponse>(endpoint: IAirRestEndPoint<IEndpointPayload, R>) {
const query = endpoint._payload ? stringifyPayload(endpoint._payload).join('&') : '';
return render<R>(
`${this.server}${endpoint._route as string}${endpoint._payload ? "?" + query : ''}`, {
...this.options,
method: 'GET',
}
)
}
post<R extends IEndpointResponse>(endpoint: IAirRestEndPoint<IEndpointPayload, R>): Promise<R> {
return render<R>(
`${this.server}${endpoint._route as string}`, {
...this.options,
method: 'POST',
body: endpoint._transpilate ? transpilatePayload(endpoint._payload) : (endpoint._payload as BodyInit),
}
)
}
put<R extends IEndpointResponse>(endpoint: IAirRestEndPoint<IEndpointPayload, R>) {
return render<R>(
`${this.server}${endpoint._route as string}`, {
...this.options,
method: 'PUT',
body: endpoint._transpilate ? transpilatePayload(endpoint._payload) : (endpoint._payload as BodyInit),
}
)
}
patch<R extends IEndpointResponse>(endpoint: IAirRestEndPoint<IEndpointPayload, R>) {
return render<R>(
`${this.server}${endpoint._route as string}`, {
...this.options,
method: 'PATCH',
body: endpoint._transpilate ? transpilatePayload(endpoint._payload) : (endpoint._payload as BodyInit),
}
)
}
delete<R extends IEndpointResponse>(endpoint: IAirRestEndPoint<IEndpointPayload, R>) {
return render<R>(
`${this.server}${endpoint._route as string}`, {
...this.options,
method: 'DELETE',
body: endpoint._transpilate ? transpilatePayload(endpoint._payload) : (endpoint._payload as BodyInit),
})
}
}
export default class AirRest {
static Server = AirRestServer;
static Endpoint = AirRestEndPoint;
}