Skip to content

Instantly share code, notes, and snippets.

@guiseek
Created June 15, 2022 23:05
Show Gist options
  • Save guiseek/04950b5fe67cfd5fef00deca206dd99d to your computer and use it in GitHub Desktop.
Save guiseek/04950b5fe67cfd5fef00deca206dd99d to your computer and use it in GitHub Desktop.
Http atômico funcional
import { HttpMethod, HttpRequestMap } from '../types'
export function fetchConfig<M extends HttpMethod>(
method: M,
opts: HttpRequestMap[M]
): RequestInit {
let { body, data, headers = [] } = opts
if (body) body = JSON.stringify(body)
if (data) data = JSON.stringify(data)
headers = new Headers(headers)
if (!headers.get('Content-Type')) {
headers.set('Content-Type', 'application/json')
}
return {
...opts,
method,
headers,
body: body ?? data,
}
}
import { HttpParams, HttpRequestDelete } from '../types'
import { createURL } from '../utilities/create-url'
import { fetchConfig } from './config'
import { httpRequest } from './request'
export function httpDelete(host: string | URL, config: HttpRequestDelete) {
const requestInit = fetchConfig('DELETE', config)
return async (
endpoint: string,
{ params }: { params?: HttpParams<string> }
): Promise<Response> => {
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
import { HttpParams, HttpRequestGet } from '../types'
import { createURL } from '../utilities/create-url'
import { httpRequest } from './request'
import { fetchConfig } from './config'
export function httpGet(host: string | URL, config?: HttpRequestGet) {
const requestInit = fetchConfig('GET', config)
return async (
endpoint: string,
{ params }: { params?: HttpParams } = {}
): Promise<Response> => {
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
import { HttpParams, HttpRequestHead } from '../types'
import { createURL } from '../utilities/create-url'
import { fetchConfig } from './config'
import { httpRequest } from './request'
export function httpHead(host: string | URL, config: HttpRequestHead) {
const requestInit = fetchConfig('HEAD', config)
return async (
endpoint: string,
{ params }: { params?: HttpParams<string> }
): Promise<Response> => {
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
import { HttpParams, HttpRequestPatch } from '../types'
import { createURL } from '../utilities/create-url'
import { fetchConfig } from './config'
import { httpRequest } from './request'
export function httpPatch(host: string | URL, config: HttpRequestPatch) {
return async <D>(
endpoint: string,
{ params, data }: { params?: HttpParams<string>; data: D }
): Promise<Response> => {
const requestInit = fetchConfig('PATCH', { data, ...config })
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
import { HttpParams, HttpRequestPost } from '../types'
import { createURL } from '../utilities/create-url'
import { fetchConfig } from './config'
import { httpRequest } from './request'
export function httpPost(host: string | URL, config: HttpRequestPost) {
return async <D>(
endpoint: string,
{ params, data }: { params?: HttpParams<string>; data: D }
): Promise<Response> => {
const requestInit = fetchConfig('POST', { data, ...config })
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
import { HttpParams, HttpRequestPut } from '../types'
import { createURL } from '../utilities/create-url'
import { fetchConfig } from './config'
import { httpRequest } from './request'
export function httpPut(host: string | URL, config: HttpRequestPut) {
return async <D>(
endpoint: string,
{ params, data }: { params?: HttpParams<string>; data: D }
): Promise<Response> => {
const requestInit = fetchConfig('PUT', { data, ...config })
const url = createURL(endpoint, params, host)
return httpRequest(url.toString(), requestInit)
}
}
export async function httpRequest(input: RequestInfo, init?: RequestInit) {
const response = await fetch(input, init)
if (!response.ok) {
const err = await response.json()
throw new Error(err.message)
}
return response
}
export * from './method';
export * from './options';
export * from './params';
export * from './query';
export * from './url';
export * from './request';
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD'
import { HttpParams } from './params'
export type HttpOptions<T = any> = {
params?: HttpParams<string> | undefined
data?: T
}
export type HttpParams<V = object> = Record<keyof V, V[keyof V]>
import { HttpURL } from './url'
export type HttpQuery<Path extends string> = {
[K in HttpURL<Path>]: string | number | boolean
}
import { HttpMethod } from './method'
export interface HttpRequestBase<T> extends Omit<RequestInit, 'method'> {
method?: HttpMethod
data?: T
}
export type HttpRequestGet = HttpRequestBase<void> & {
method?: 'GET'
}
export type HttpRequestHead = HttpRequestBase<void> & {
method?: 'HEAD'
}
export type HttpRequestDelete = HttpRequestBase<void> & {
method?: 'DELETE'
}
export type HttpRequestPut<T = any> = HttpRequestBase<T> & {
method?: 'PUT'
}
export type HttpRequestPost<T = any> = HttpRequestBase<T> & {
method?: 'POST'
}
export type HttpRequestPatch<T = any> = HttpRequestBase<T> & {
method?: 'PATCH'
}
export interface HttpRequestMap {
GET: HttpRequestGet
HEAD: HttpRequestHead
DELETE: HttpRequestDelete
PATCH: HttpRequestPatch
POST: HttpRequestPost
PUT: HttpRequestPut
}
export type HttpURL<Path extends string> =
Path extends `:${infer Param}/${infer Rest}`
? Param | HttpURL<Rest>
: Path extends `:${infer Param}`
? Param
: Path extends `${infer Prefix}:${infer Rest}`
? HttpURL<`:${Rest}`>
: never
import { HttpQuery } from '../types/query'
export function createURL<U extends string>(
endpoint: U,
params?: HttpQuery<U>,
parent?: string | URL
) {
const url = new URL(endpoint, parent)
if (params) {
const urlParams = Object.entries(params)
urlParams.forEach(([key, val]) => {
url.searchParams.set(key, `${val}`)
})
}
return url
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment