function generateAPI(baseUrl, defaults = {}, scope = []) { const callable = () => {} callable.url = baseUrl return new Proxy(callable, { get({ url }, propKey) { const method = propKey.toUpperCase() const path = scope.concat(propKey) if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) { return (data, overrides = {}) => { const payload = { method, ...overrides } switch (method) { case 'GET': { if (data) url = `${url}?${new URLSearchParams(data)}` break } case 'POST': case 'PUT': case 'PATCH': { payload.body = JSON.stringify(data) } } console.log(`Calling: ${url}${path.slice(0, -1).join('/')}`) console.log('payload', payload) return fetch(url, payload).then((d) => d.json()) } } return generateAPI(`${url}/${propKey}`, defaults, path) }, apply({ url }, thisArg, [arg] = []) { const path = url.split('/') return generateAPI(arg ? `${url}/${arg}` : url, defaults, path) } }) } function githubClient(token) { return generateAPI('https://api.github.com', { headers: { 'User-Agent': 'required field', 'Authorization': `bearer ${token}` } }) } const token = 'tokenxyz' const client = generateAPI('https://api.github.com', { headers: { 'User-Agent': 'required field', 'Authorization': `bearer ${token}` } }) async function getRepo() { // GET /repos/{owner}/{repo} return client.repos.davidwells.analytics.get() } getRepo().then((r) => { console.log('repo, r) })