RyanofWoods/rails-react-swedish-birds

View on GitHub
app/javascript/react_app/api/client.ts

Summary

Maintainability
B
4 hrs
Test Coverage
// A tiny wrapper around fetch(), borrowed from
// https://github.com/reduxjs/redux-essentials-example-app/blob/tutorial-steps/src/api/client.js
// https://kentcdodds.com/blog/replace-axios-with-a-simple-custom-fetch-wrapper

interface Data {
  body?: {}
  headers?: {}
}

type RequestType = 'GET' | 'POST' | 'PATCH'

interface Config {
  method: RequestType
  headers: {}
  body?: string
}

interface Response<T> {
  status: number
  result: T
  headers: Headers
  url: string
}

const BASE_URL = '/api'

export async function client<T> (method: RequestType, endpoint: string, data: Data = {}): Promise<Response<T>> {
  const { body, ...customConfig } = data
  const headers = { 'Content-Type': 'application/json' }

  const config: Config = {
    method,
    ...customConfig,
    headers: {
      ...headers,
      ...customConfig.headers
    }
  }

  if (body !== undefined) {
    config.body = JSON.stringify(body)
  }

  const url = BASE_URL + endpoint
  let result
  try {
    const response = await window.fetch(url, config)
    result = await response.json()
    if (response.ok) {
      return {
        status: response.status,
        result,
        headers: response.headers,
        url: response.url
      }
    }
    return await Promise.reject(result.error)
  } catch (err: any) {
    const errorMessage = err ?? 'Something went wrong.'
    return await Promise.reject(errorMessage)
  }
}

client.get = async function <T>(endpoint: string, customConfig = {}) {
  return await client<T>('GET', endpoint, { ...customConfig })
}

client.post = async function <T>(endpoint: string, body: {}, customConfig = {}) {
  return await client<T>('POST', endpoint, { ...customConfig, body })
}

client.patch = async function <T>(endpoint: string, body: {}, customConfig = {}) {
  return await client<T>('PATCH', endpoint, { ...customConfig, body })
}