Skip to content

Instantly share code, notes, and snippets.

@sonodar
Created November 30, 2022 06:27
Show Gist options
  • Save sonodar/404f725229c56c9cb68ce36eb6651de4 to your computer and use it in GitHub Desktop.
Save sonodar/404f725229c56c9cb68ce36eb6651de4 to your computer and use it in GitHub Desktop.
Rest Client with Bearer token authorization
type Method = 'get' | 'post' | 'patch' | 'put' | 'delete' | 'head'
type IdempotentMethod = 'get' | 'head' | 'delete'
type MutationMethod = Exclude<Method, IdempotentMethod>
type IdempotentClient = (path: string, query?: URLSearchParams, headers?: HeadersInit) => Promise<Response>
type MutationClient = (path: string, body: any, headers?: HeadersInit) => Promise<Response>
type IdempotentClients = Record<IdempotentMethod, IdempotentClient>
type MutationClients = Record<MutationMethod, MutationClient>
type _RequestClient = IdempotentClients & MutationClients
type RequestClient = _RequestClient & {
withAuth: (token: string) => _RequestClient
}
export const createRestClient = (baseUrl: string, bearerTokenHeader: string = 'authorization'): RequestClient => {
const withJson = (headers?: HeadersInit): HeadersInit => ({
'Content-Type': 'application/json',
...(headers || {})
})
const withAuthorization = (token: string, headers?: HeadersInit): HeadersInit => ({
[bearerTokenHeader]: 'Bearer ' + token,
...(headers || {})
})
const idempotentMethods = ['get', 'head', 'delete'] as const
const mutationMethods = ['post', 'patch', 'put'] as const
const factoryReducer = <T extends string, C>(factory: (method: T) => C) => (memo: Record<T, C>, method: T) => {
memo[method] = factory(method)
return memo
}
const request = (path: string, init: RequestInit, query?: URLSearchParams) => {
const url = `${baseUrl}${path}${query ? `?${query}` : ''}`
return fetch(url, init)
}
const idempotentClientFactory = (method: IdempotentMethod): IdempotentClient => (path, query, headers) => request(path, { method, headers }, query)
const mutationClientFactory = (method: MutationMethod): MutationClient => (path, body, headers) => request(path, { method, headers: withJson(headers), body: JSON.stringify(body) })
const _client: _RequestClient = {
...idempotentMethods.reduce(factoryReducer(idempotentClientFactory), {} as IdempotentClients),
...mutationMethods.reduce(factoryReducer(mutationClientFactory), {} as MutationClients),
}
function withAuthClientFactory<T extends Method>(token: string): (method: T) => T extends IdempotentMethod ? IdempotentClient : MutationClient {
return (method: T) => (path, bodyOrQuery, headers) => _client[method](path, bodyOrQuery, withAuthorization(token, headers))
}
return {
..._client,
withAuth(token) {
return {
...idempotentMethods.reduce(factoryReducer(withAuthClientFactory(token)), {} as IdempotentClients),
...mutationMethods.reduce(factoryReducer(withAuthClientFactory(token)), {} as MutationClients),
}
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment