kibana/x-pack/plugins/apm/dev_docs/routing_and_linking.md
Dario Gieselaar 821aeb1ff4
[APM] Typed client-side routing (#104274)
* [APM] @kbn/typed-router-config

* [APM] typed route config

* Breadcrumbs, wildcards

* Migrate settings, home

* Migrate part of service detail page

* Migrate remaining routes, tests

* Set maxWorkers for precommit script to 4

* Add jest types to tsconfigs

* Make sure transaction distribution data is fetched

* Fix typescript errors

* Remove usage of react-router's useParams

* Add route() utility function

* Don't use ApmServiceContext for alert flyouts

* Don't add onClick handler for breadcrumb

* Clarify ts-ignore

* Remove unused things

* Update documentation

* Use useServiceName() in ServiceMap component
2021-07-15 11:30:59 +02:00

3.7 KiB

APM Plugin Routing and Linking

Routing

This document describes routing in the APM plugin.

Server-side

Route definitions for APM's server-side API are in the server/routes directory. Routes are created with the createRoute function. Routes are added to the API in the createApmApi function, which is initialized in the plugin start lifecycle method.

The path and query string parameters are defined in the calls to createRoute with io-ts types, so that each route has its parameters type checked.

Client-side

The client-side routing uses @kbn/typed-react-router-config, which is a wrapper around React Router and React Router Config. Its goal is to provide a layer of high-fidelity types that allows us to parse and format URLs for routes while making sure the needed parameters are provided and/or available (typed and validated at runtime). The history object used by React Router is injected by the Kibana Platform.

Routes (and their parameters) are defined in public/components/routing/apm_config.tsx.

Parameter handling

Path (like serviceName in '/services/:serviceName/transactions') and query parameters are defined in the route definitions.

For each parameter, an io-ts runtime type needs to be present:

{
  route: '/services/:serviceName',
  element: <Outlet/>,
  params: t.intersection([
    t.type({
      path: t.type({
        serviceName: t.string,
      })
    }),
    t.partial({
      query: t.partial({
        transactionType: t.string
      })
    })
  ])
}

To be able to use the parameters, you can use useApmParams, which will automatically infer the parameter types from the route path:

const {
  path: { serviceName }, // string
  query: { transactionType } // string | undefined
} = useApmParams('/services/:serviceName');

useApmParams will strip query parameters for which there is no validation. The route path should match exactly, but you can also use wildcards: useApmParams('/*). In that case, the return type will be a union type of all possible matching routes.

Previously we used useUrlParams for path and query parameters, which we are trying to get away from. When possible, any usage of useUrlParams should be replaced by useApmParams or other custom hooks that use useApmParams internally.

Linking

Raw URLs should almost never be used in the APM UI. Instead, we have mechanisms for creating links and URLs that ensure links are reliable.

In-app linking

For links that stay inside APM, the preferred way of linking is to call the useApmRouter hook, and call router.link with the route path and required path and query parameters:

const apmRouter = useApmRouter();
const serviceOverviewLink = apmRouter.link('/services/:serviceName', { path: { serviceName: 'opbeans-java' }, query: { transactionType: 'request' }});

If you're not in React context, you can also import apmRouter directly and call its link function - but you have to prepend the basePath manually in that case.

We also have the getAPMHref function and APMLink component, but we should consider them deprecated, in favor of router.link. Other components inside that directory contain other functions and components that provide the same functionality for linking to more specific sections inside the APM plugin.

Cross-app linking

Other helpers and components in the Links directory allow linking to other Kibana apps.