Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error Handler #4

Open
davidbarratt opened this issue Aug 11, 2019 · 2 comments
Open

Error Handler #4

davidbarratt opened this issue Aug 11, 2019 · 2 comments
Labels
enhancement New feature or request

Comments

@davidbarratt
Copy link

Is there a way to define an error handler? My handler may throw an exception and it would be nice to catch the exceptions from the handlers and handle them together.

@berstend
Copy link
Owner

Hey @davidbarratt - it's possible to do that, although a bit verbose (I might add a convenience wrapper for this in the future 😄)

Here's a full example (Cloudflare Worker, TypeScript) how one might do NotFound and error handling with the router:

import CloudflareWorkerGlobalScope from "types-cloudflare-worker"
declare var self: CloudflareWorkerGlobalScope

import { HandlerContext, Router } from "service-worker-router"

const ping = async () => new Response("pong")
const notFound = async () => new Response("Not found :(", { status: 404 })
const errorResponse = async (err: Error) => new Response(`Error occured: ${err.message}`)

const conditionalThrow = async ({ request, params }: HandlerContext): Promise<Response> => {
  if (params.wish === "yes") {
    throw new Error("I threw.")
  }
  return new Response("All good.", { status: 200 })
}

const router = new Router()
router.all("/_ping", ping)
router.all("/throw/:wish", conditionalThrow)

async function fetchEventHandler(event: FetchEvent): Promise<Response> {
  try {
    const match = router.handleRequest(event.request)
    if (match) {
      return await match.handlerPromise // await is important here for error catching to work
    }
    return notFound()
  } catch (err) {
    return errorResponse(err)
  }
}

self.addEventListener("fetch", (event: FetchEvent) => {
  event.respondWith(fetchEventHandler(event))
})

Results in:

❯ curl 'https://my-worker.com/_ping'
pong
❯ curl 'https://my-worker.com/foobar'
Not found :(
❯ curl 'https://my-worker.com/throw/nope'
All good.
❯ curl 'https://my-worker.com/throw/yes'
Error occured: I threw.

@berstend berstend added the enhancement New feature or request label Oct 27, 2019
@p-j
Copy link

p-j commented Dec 5, 2019

Hi,

I've been using this router and have had a similar wish: being able to easily handle errors, here the solution I came up with:

// withErrorHandler.js
/**
 * Higher order function providing generic error handling for request handlers
 * @param {Function} func a request handler
 * @returns {Response}
 */
export function withErrorHandler (func) {
  return async function handler (...args) {
    try {
      // await is not superfluous here as otherwise the catch is bypassed
      return await func(...args)
    } catch (error) {
      const url = new URL(args.request.url)
      const debug = url.searchParams.get('debug') === 'true'
      return debug // show the stack trace, could be used to send it to a monitoring system or else
        ? new Response(error.stack || error)
        : new Response(null, { status: 500 })
    }
  }
}
// index.js
import { Router } from 'service-worker-router'
import { routeHandler } from './routeHandler'
import { withErrorHandler } from './withErrorHandler'

const router = new Router()
router.get('/path/to/handle', withErrorHandler(routeHandler))

addEventListener('fetch', (event) => {
  // Will test event.request against the defined routes
  // and use event.respondWith(handler) when a route matches
  return router.handleEvent(event)
})

Just sharing it in case it may help someone else.
Note that this version doesn't handle 404's in case the router doesn't match any route.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants