# `PhoenixKit.API.Paths`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.64.1/lib/phoenix_kit/api/paths.ex#L1)

The one table of API paths. The router macro (`PhoenixKitWeb.Integration`)
forwards every entry to its plug, and `PhoenixKit.API.BodyGuard` guards every
entry, so the two cannot disagree about where the API lives.

The axis of the API is the audience, not a module: modules own the names of
their tools (`catalogue.set_prices`), the paths are

    /api/admin/v1   /mcp/admin     the admin audience, with a key
    /api/public/v1  /mcp/public    the public audience, without one

under the kit's URL prefix. The segment that names the public audience is
`public_segment/0`, the only place it is spelled: renaming the public
prefix is a change of that one line.

## Entries

`entries/0` lists `{segments, audience, cors?, kind}`:

  * `segments`, the path under the URL prefix, split by `/`;
  * `audience`, `:admin` or `:public`, which decides the plug's options and
    the switch `PhoenixKit.API.BodyGuard` looks at;
  * `cors?`, whether the answers carry the CORS headers of the public REST
    audience (`PhoenixKit.API.REST`), the guard's included;
  * `kind`, `:canonical`, or `{:alias, canonical_path}` for a deprecated
    path (`PhoenixKit.API.Legacy`) that is served by the same plug as
    `canonical_path`.

Anything that builds a URL for a client (`PhoenixKit.API.OpenAPI`,
`PhoenixKit.API.PublicDiscovery`) takes `rest_path/1` and `mcp_path/1`,
which are canonical by construction: no document, catalog, guide or `Link`
header advertises an alias.

## A deprecated path

The forward of an alias carries `deprecated: [path: ..., successor: ...]`
next to `audience:`. `PhoenixKit.API.Auth` then puts `Deprecation`
(`PhoenixKit.API.Legacy.deprecation/0`) and `Link: <canonical>;
rel="successor-version"` on every answer it lets through to the transport
(`put_deprecation/2`), and logs the first use of the path on a node once.
A request the API turns away with its bare `404` (switch off, website
password gate) carries neither: such a path reveals nothing.

# `entry`

```elixir
@type entry() :: {segments(), :admin | :public, boolean(), kind()}
```

# `kind`

```elixir
@type kind() :: :canonical | {:alias, String.t()}
```

# `segments`

```elixir
@type segments() :: [String.t()]
```

# `entries`

```elixir
@spec entries() :: [entry()]
```

Every path the API answers on, canonical entries first and then the
deprecated aliases. See the moduledoc for the shape.

# `mcp_path`

```elixir
@spec mcp_path(:admin | :public) :: String.t()
```

The canonical path of the MCP endpoint of `audience`, without the URL prefix.

# `path`

```elixir
@spec path(segments()) :: String.t()
```

The path of `segments` as `forward` takes it: `"/api/admin/v1"`.

# `plug`

```elixir
@spec plug(segments()) :: module()
```

The plug that serves the path made of `segments`: REST under `api`, MCP under `mcp`.

# `plug_opts`

```elixir
@spec plug_opts(entry()) :: keyword()
```

The options of the `forward` of `entry`: the audience, and for an alias the
`:deprecated` pair the plugs read (`PhoenixKit.API.Auth`).

# `public_segment`

```elixir
@spec public_segment() :: String.t()
```

The path segment that names the public audience in `/api/<segment>/v1` and
`/mcp/<segment>`: the one place it is spelled.

# `put_deprecation`

```elixir
@spec put_deprecation(Plug.Conn.t(), keyword() | nil) :: Plug.Conn.t()
```

Marks the answers to `conn` as those of a deprecated path: `Deprecation`, a
`Link: <canonical URL>; rel="successor-version"` appended to any `Link` the
request already has, and, the first time the node sees the path, one
`info` line in the log. `nil` (a canonical path) changes nothing.

The canonical URL is the one `PhoenixKit.API.PublicDiscovery` names, on the
host it trusts.

# `rest_path`

```elixir
@spec rest_path(:admin | :public) :: String.t()
```

The canonical path of the REST API of `audience`, without the URL prefix.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
