citycoins / api

A simple API to interact with Stacks and CityCoins data.
https://api.citycoins.co/docs
Apache License 2.0
9 stars 2 forks source link

Review endpoint error handling #61

Closed whoabuddy closed 2 years ago

whoabuddy commented 2 years ago

With the recent changes a better pattern for error handling was identified using try/catch instead of promise chains.

This allows the called function to throw the error and define the message rather than defining it within each endpoint.

Multiple queries can be grouped in a try statement as well, and this allows for us to define errors as well as pass through errors from upstream libraries.

This should really DRY up the endpoint code but will take some effort to refactor and review each handler/endpoint.

Examples below.

Before

  // returns an object if found, or an empty object
  const cityConfig = await getCityConfig(city)
  // checks for an empty object or undeployed contract
  if (cityConfig.deployer === '') {
    return new Response(`City name not found: ${city}`, { status: 404 })
  }
  // returns the userId or null if not found
  const userId = await getUserId(cityConfig, user)
  // check for the null
  if (userId === null) {
    return new Response(`User not found: ${user}`, { status: 404 })
  }

After

  try {
    cityConfig = await getCityConfig(city, version)
    userId = await getUserId(cityConfig, user)
    userId === null && throw new Error(`User not found: ${user}`)
  } catch (err) {
    if (err instanceof Error) return new Response(err.message, { status: 404 })
    return new Response(String(err), { status: 404 })
  }

Function example

// always returns a CityConfig, errors are passed through
export async function getCityConfig(city: string, version: string): Promise<CityConfig> {
  version = version.toLowerCase()
  switch (city.toLowerCase()) {
    case "mia":
      if (Object.prototype.hasOwnProperty.call(miaConfig, version)) return miaConfig[version]
      throw new Error(`Invalid city name or version ${city} ${version}`)
    case "nyc":
      if (Object.prototype.hasOwnProperty.call(nycConfig, version)) return nycConfig[version]
      throw new Error(`Invalid city name or version ${city} ${version}`)
    default:
      throw new Error(`Invalid city name or version ${city} ${version}`)
  }
}