A service worker can intercept network requests for a page. It may respond to
the browser with cached content, content from the network or content generated
in the service worker.

`workbox-routing` is a module which makes it easy to "route" these requests to
different functions that provide responses.

## How Routing is Performed

When a network request causes a service worker fetch event, `workbox-routing`
will attempt to respond to the request using the supplied routes and handlers.

![Workbox Routing Diagram](https://developer.chrome.com/static/docs/workbox/modules/workbox-routing/image/workbox-routing-diagram-b523052270b9d.png)

The main things to note from the above are:

- The method of a request is important. By default, Routes are registered for
  `GET` requests. If you wish to intercept other types of requests, you'll need
  to specify the method.

- The order of the Route registration is important. If multiple Routes are
  registered that could handle a request, the Route that is registered first
  will be used to respond to the request.

There are a few ways to register a route: you can use callbacks, regular
expressions or Route instances.

## Matching and Handling in Routes

A "route" in workbox is nothing more than two functions: a "matching" function
to determine if the route should match a request and a "handling" function,
which should handle the request and respond with a response.

Workbox comes with some helpers that'll perform the matching and handling for
you, but if you ever find yourself wanting different behavior, writing a
custom match and handler function is the best option.

A
[match callback function](https://developer.chrome.com/docs/workbox/reference/workbox-core#method-RouteMatchCallback)
is passed a
[`ExtendableEvent`](https://developer.mozilla.org/docs/Web/API/ExtendableEvent),
[`Request`](https://developer.mozilla.org/docs/Web/API/Request), and a
[`URL` object](https://developer.mozilla.org/docs/Web/API/URL) you can
match by returning a truthy value. For a simple example, you could match against
a specific URL like so:

    const matchCb = ({url, request, event}) => {
      return url.pathname === '/special/url';
    };

Most use cases can be covered by examining / testing either the `url` or the
`request`.

A
[handler callback function](https://developer.chrome.com/docs/workbox/reference/workbox-core#type-RouteHandler)
will be given the same
[`ExtendableEvent`](https://developer.mozilla.org/docs/Web/API/ExtendableEvent),
[`Request`](https://developer.mozilla.org/docs/Web/API/Request), and
[`URL` object](https://developer.mozilla.org/docs/Web/API/URL) along with
a `params` value, which is the value returned by the "match" function.

    const handlerCb = async ({url, request, event, params}) => {
      const response = await fetch(request);
      const responseBody = await response.text();
      return new Response(`${responseBody} <!-- Look Ma. Added Content. -->`, {
        headers: response.headers,
      });
    };

Your handler must return a promise that resolves to a `Response`. In this
example, we're using
[`async` and `await`](https://web.dev/articles/async-functions).
Under the hood, the return `Response` value will be wrapped in a promise.

You can register these callbacks like so:

    import {registerRoute} from 'workbox-routing';

    registerRoute(matchCb, handlerCb);

The only limitation is that the "match" callback **must synchronously** return a truthy
value, you can't perform any asynchronous work. The reason for this is that
the `Router` must synchronously respond to the fetch event or allow falling
through to other fetch events.

Normally the "handler" callback would use one of the strategies provided
by [workbox-strategies](https://developer.chrome.com/docs/workbox/modules/workbox-strategies) like so:

    import {registerRoute} from 'workbox-routing';
    import {StaleWhileRevalidate} from 'workbox-strategies';

    registerRoute(matchCb, new StaleWhileRevalidate());

In this page, we'll focus on `workbox-routing` but you can
[learn more about these strategies on workbox-strategies](https://developer.chrome.com/docs/workbox/modules/workbox-strategies).

## How to Register a Regular Expression Route

A common practice is to use a regular expression instead of a "match" callback.
Workbox makes this easy to implement like so:

    import {registerRoute} from 'workbox-routing';

    registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);

For requests from the
[same origin](https://developer.mozilla.org/docs/Web/Security/Same-origin_policy),
this regular expression will match as long as the request's URL matches the
regular expression.

- https://example.com**/styles/main.css**
- https://example.com**/styles/nested/file.css**
- https://example.com/nested**/styles/directory.css**

However, for cross-origin requests, regular expressions
**must match the beginning of the URL** . The reason for this is that it's
unlikely that with a regular expression `new RegExp('/styles/.*\\.css')`
you intended to match third-party CSS files.

- https://cdn.third-party-site.com**/styles/main.css**
- https://cdn.third-party-site.com**/styles/nested/file.css**
- https://cdn.third-party-site.com/nested**/styles/directory.css**

If you *did* want this behaviour, you just need to ensure that the regular
expression matches the beginning of the URL. If we wanted to match the
requests for `https://cdn.third-party-site.com` we could use the regular
expression `new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css')`.

- **https://cdn.third-party-site.com/styles/main.css**
- **https://cdn.third-party-site.com/styles/nested/file.css**
- **https://cdn.third-party-site.com/nested/styles/directory.css**

If you wanted to match both local and third parties you can use a wildcard
at the start of your regular expression, but this should be done with caution
to ensure it doesn't cause unexpected behaviors in your web app.

## How to Register a Navigation Route

If your site is a single page app, you can use a
[`NavigationRoute`](https://developer.chrome.com/docs/workbox/reference/workbox-routing#type-NavigationRoute) to
return a specific response for all
[navigation requests](https://developer.chrome.com/docs/workbox/caching-strategies-overview).

    import {createHandlerBoundToURL} from 'workbox-precaching';
    import {NavigationRoute, registerRoute} from 'workbox-routing';

    // This assumes /app-shell.html has been precached.
    const handler = createHandlerBoundToURL('/app-shell.html');
    const navigationRoute = new NavigationRoute(handler);
    registerRoute(navigationRoute);

Whenever a user goes to your site in the browser, the request for the page will
be a navigation request and it will be served the cached page `/app-shell.html`.
(Note: You should have the page cached via `workbox-precaching` or through your
own installation step.)

By default, this will respond to *all* navigation requests. If you want to
restrict it to respond to a subset of URLs, you can use the `allowlist`
and `denylist` options to restrict which pages will match this route.

    import {createHandlerBoundToURL} from 'workbox-precaching';
    import {NavigationRoute, registerRoute} from 'workbox-routing';

    // This assumes /app-shell.html has been precached.
    const handler = createHandlerBoundToURL('/app-shell.html');
    const navigationRoute = new NavigationRoute(handler, {
      allowlist: [new RegExp('/blog/')],
      denylist: [new RegExp('/blog/restricted/')],
    });
    registerRoute(navigationRoute);

The only thing to note is that the `denylist` will win if a URL is in both
the `allowlist` and `denylist`.

## Set a Default Handler

If you want to supply a "handler" for requests that don't match a route, you
can set a default handler.

    import {setDefaultHandler} from 'workbox-routing';

    setDefaultHandler(({url, event, params}) => {
      // ...
    });

## Set a Catch Handler

In the case of any of your routes throwing an error, you can capture and
degrade gracefully by setting a catch handler.

    import {setCatchHandler} from 'workbox-routing';

    setCatchHandler(({url, event, params}) => {
      ...
    });

## Defining a Route for Non-GET Requests

All routes by default are assumed to be for `GET` requests.

If you would like to route other requests, like a `POST` request, you need
to define the method when registering the route, like so:

    import {registerRoute} from 'workbox-routing';

    registerRoute(matchCb, handlerCb, 'POST');
    registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');

## Router Logging

You should be able to determine the flow of a request using the logs from
`workbox-routing` which will highlight which URLs are being processed
through Workbox.

![Routing Logs](https://developer.chrome.com/static/docs/workbox/modules/workbox-routing/image/routing-logs-4dc6529a9741a.png)

If you need more verbose information, you can set the log level to `debug` to
view logs on requests not handled by the Router. See our
[debugging guide](https://developer.chrome.com/docs/workbox/troubleshooting-and-logging) for more info on
setting the log level.

![Debug and Log Routing Messages](https://developer.chrome.com/static/docs/workbox/modules/workbox-routing/image/debug-log-routing-messag-2ac1e6858fe2a.png)

## Advanced Usage

If you want to have more control over when the Workbox Router is given
requests, you can create your own
[`Router`](https://developer.chrome.com/docs/workbox/reference/workbox-routing#type-Router) instance and call
it's [`handleRequest()`](https://developer.chrome.com/docs/workbox/reference/workbox-routing#method-Router-handleRequest)
method whenever you want to use the router to respond to a request.

    import {Router} from 'workbox-routing';

    const router = new Router();

    self.addEventListener('fetch', event => {
      const {request} = event;
      const responsePromise = router.handleRequest({
        event,
        request,
      });
      if (responsePromise) {
        // Router found a route to handle the request.
        event.respondWith(responsePromise);
      } else {
        // No route was found to handle the request.
      }
    });

When using the `Router` directly, you will also need to use the `Route` class,
or any of the extending classes to register routes.

    import {Route, RegExpRoute, NavigationRoute, Router} from 'workbox-routing';

    const router = new Router();
    router.registerRoute(new Route(matchCb, handlerCb));
    router.registerRoute(new RegExpRoute(new RegExp(...), handlerCb));
    router.registerRoute(new NavigationRoute(handlerCb));

<br />

## Types

### NavigationRoute

NavigationRoute makes it easy to create a
[`workbox-routing.Route`](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route) that matches for browser
\[navigation requests\]`https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests`.

It will only match incoming Requests whose
`https://fetch.spec.whatwg.org/#concept-request-mode|mode`
is set to `navigate`.

You can optionally only apply this route to a subset of navigation requests
by using one or both of the `denylist` and `allowlist` parameters.

#### Properties

- constructor void

  If both `denylist` and `allowlist` are provided, the `denylist` will
  take precedence and the request will not match this route.

  The regular expressions in `allowlist` and `denylist`
  are matched against the concatenated
  \[`pathname`\]`https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname`
  and \[`search`\]`https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search`
  portions of the requested URL.

  *Note* : These RegExps may be evaluated against every destination URL during
  a navigation. Avoid using
  [complex RegExps](https://github.com/GoogleChrome/workbox/issues/3077),
  or else your users may see delays when navigating your site.


  The `constructor` function looks like:

  ```typescript
  (handler: RouteHandler, options?: NavigationRouteMatchOptions) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resulting in a Response.
  - options [NavigationRouteMatchOptions](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-NavigationRouteMatchOptions) optional
  - returns[NavigationRoute](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-NavigationRoute)
- catchHandler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject) optional
- handler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject)
- match [RouteMatchCallback](https://developer.chrome.com/docs/workbox/workbox-core/#method-RouteMatchCallback)
- method HTTPMethod
- setCatchHandler void


  The `setCatchHandler` function looks like:

  ```typescript
  (handler: RouteHandler) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resolving to a Response

### NavigationRouteMatchOptions

#### Properties

- allowlist RegExp\[\] optional
- denylist RegExp\[\] optional

### RegExpRoute

RegExpRoute makes it easy to create a regular expression based
[`workbox-routing.Route`](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route).

For same-origin requests the RegExp only needs to match part of the URL. For
requests against third-party servers, you must define a RegExp that matches
the start of the URL.

#### Properties

- constructor void

  If the regular expression contains
  \[capture groups\]`https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references`,
  the captured values will be passed to the
  `workbox-routing~handlerCallback` `params`
  argument.


  The `constructor` function looks like:

  ```typescript
  (regExp: RegExp, handler: RouteHandler, method?: HTTPMethod) => {...}
  ```

  <br />

  - regExp RegExp

    The regular expression to match against URLs.
  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resulting in a Response.
  - method HTTPMethod optional
  - returns[RegExpRoute](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-RegExpRoute)
- catchHandler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject) optional
- handler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject)
- match [RouteMatchCallback](https://developer.chrome.com/docs/workbox/workbox-core/#method-RouteMatchCallback)
- method HTTPMethod
- setCatchHandler void


  The `setCatchHandler` function looks like:

  ```typescript
  (handler: RouteHandler) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resolving to a Response

### Route

A `Route` consists of a pair of callback functions, "match" and "handler".
The "match" callback determine if a route should be used to "handle" a
request by returning a non-falsy value if it can. The "handler" callback
is called when there is a match and should return a Promise that resolves
to a `Response`.

#### Properties

- constructor void

  Constructor for Route class.


  The `constructor` function looks like:

  ```typescript
  (match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}
  ```

  <br />

  - match [RouteMatchCallback](https://developer.chrome.com/docs/workbox/workbox-core/#method-RouteMatchCallback)

    A callback function that determines whether the route matches a given
    `fetch` event by returning a non-falsy value.
  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resolving to a Response.
  - method HTTPMethod optional
  - returns[Route](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route)
- catchHandler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject) optional
- handler [RouteHandlerObject](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandlerObject)
- match [RouteMatchCallback](https://developer.chrome.com/docs/workbox/workbox-core/#method-RouteMatchCallback)
- method HTTPMethod
- setCatchHandler void


  The `setCatchHandler` function looks like:

  ```typescript
  (handler: RouteHandler) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resolving to a Response

### Router

The Router can be used to process a `FetchEvent` using one or more
[`workbox-routing.Route`](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route), responding with a `Response` if
a matching route exists.

If no route matches a given a request, the Router will use a "default"
handler if one is defined.

Should the matching Route throw an error, the Router will use a "catch"
handler if one is defined to gracefully deal with issues and respond with a
Request.

If a request matches multiple routes, the **earliest** registered route will
be used to respond to the request.

#### Properties

- constructor void

  Initializes a new Router.


  The `constructor` function looks like:

  ```typescript
  () => {...}
  ```

  <br />

  - returns[Router](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Router)
- routes Map\<HTTPMethodRoute\[\]\>
- addCacheListener void

  Adds a message event listener for URLs to cache from the window.
  This is useful to cache resources loaded on the page prior to when the
  service worker started controlling it.

  The format of the message data sent from the window should be as follows.
  Where the `urlsToCache` array may consist of URL strings or an array of
  URL string + `requestInit` object (the same as you'd pass to `fetch()`).

      {
        type: 'CACHE_URLS',
        payload: {
          urlsToCache: [
            './script1.js',
            './script2.js',
            ['./script3.js', {mode: 'no-cors'}],
          ],
        },
      }


  The `addCacheListener` function looks like:

  ```typescript
  () => {...}
  ```

  <br />

- addFetchListener void

  Adds a fetch event listener to respond to events when a route matches
  the event's request.


  The `addFetchListener` function looks like:

  ```typescript
  () => {...}
  ```

  <br />

- findMatchingRoute void

  Checks a request and URL (and optionally an event) against the list of
  registered routes, and if there's a match, returns the corresponding
  route along with any params generated by the match.


  The `findMatchingRoute` function looks like:

  ```typescript
  (options: RouteMatchCallbackOptions) => {...}
  ```

  <br />

  - options [RouteMatchCallbackOptions](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteMatchCallbackOptions)
  - returnsobject

    An object with `route` and `params` properties.
    They are populated if a matching route was found or `undefined`
    otherwise.
- handleRequest void

  Apply the routing rules to a FetchEvent object to get a Response from an
  appropriate Route's handler.


  The `handleRequest` function looks like:

  ```typescript
  (options: object) => {...}
  ```

  <br />

  - options object
    - event ExtendableEvent

      The event that triggered the
      request.
    - request Request

      The request to handle.
  - returnsPromise\<Response\>

    A promise is returned if a
    registered route can handle the request. If there is no matching
    route and there's no `defaultHandler`, `undefined` is returned.
- registerRoute void

  Registers a route with the router.


  The `registerRoute` function looks like:

  ```typescript
  (route: Route) => {...}
  ```

  <br />

  - route [Route](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route)

    The route to register.
- setCatchHandler void

  If a Route throws an error while handling a request, this `handler`
  will be called and given a chance to provide a response.


  The `setCatchHandler` function looks like:

  ```typescript
  (handler: RouteHandler) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resulting in a Response.
- setDefaultHandler void

  Define a default `handler` that's called when no routes explicitly
  match the incoming request.

  Each HTTP method ('GET', 'POST', etc.) gets its own default handler.

  Without a default handler, unmatched requests will go against the
  network as if there were no service worker present.


  The `setDefaultHandler` function looks like:

  ```typescript
  (handler: RouteHandler, method?: HTTPMethod) => {...}
  ```

  <br />

  - handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

    A callback
    function that returns a Promise resulting in a Response.
  - method HTTPMethod optional
- unregisterRoute void

  Unregisters a route with the router.


  The `unregisterRoute` function looks like:

  ```typescript
  (route: Route) => {...}
  ```

  <br />

  - route [Route](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route)

    The route to unregister.

## Methods

### registerRoute()

```typescript
workbox-routing.registerRoute(
  capture: string | RegExp | RouteMatchCallback | Route,
  handler?: RouteHandler,
  method?: HTTPMethod,
): Route
```

Easily register a RegExp, string, or function with a caching
strategy to a singleton Router instance.

This method will generate a Route for you if needed and
call `workbox-routing.Router#registerRoute`.

#### Parameters

- capture string \| RegExp \| [RouteMatchCallback](https://developer.chrome.com/docs/workbox/workbox-core/#method-RouteMatchCallback) \| [Route](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route)

  If the capture param is a `Route`, all other arguments will be ignored.
- handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler) optional
- method HTTPMethod optional

#### Returns

- [Route](https://developer.chrome.com/docs/workbox/modules/workbox-routing#type-Route)

  The generated `Route`.

### setCatchHandler()

```typescript
workbox-routing.setCatchHandler(
  handler: RouteHandler,
): void
```

If a Route throws an error while handling a request, this `handler`
will be called and given a chance to provide a response.

#### Parameters

- handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

  A callback
  function that returns a Promise resulting in a Response.

### setDefaultHandler()

```typescript
workbox-routing.setDefaultHandler(
  handler: RouteHandler,
): void
```

Define a default `handler` that's called when no routes explicitly
match the incoming request.

Without a default handler, unmatched requests will go against the
network as if there were no service worker present.

#### Parameters

- handler [RouteHandler](https://developer.chrome.com/docs/workbox/workbox-core/#type-RouteHandler)

  A callback
  function that returns a Promise resulting in a Response.

<br />