# `DocShell.Web.Plug`
[🔗](https://github.com/futhr/doc_shell/blob/v2.0.0/lib/doc_shell/web/plug.ex#L2)

Serves cached artifacts over HTTP, behind an authorization gate you supply.

Mount it wherever the documentation JSON should live:

    forward "/docs/api",
      to: DocShell.Web.Plug,
      init_opts: [gate: &MyApp.Auth.allow_docs?/1]

The last path segment names the artifact, with `.json` optional, so
`GET /docs/api/navigation` and `GET /docs/api/navigation.json` both return
`navigation.json` from `DocShell.Web.Cache`. The stored envelope is served
as-is, so `generated_at` is the time of the build that produced the
artifact — not the time of the request, which would be useless to a client
and would defeat any caching built on top of it.

The conn is halted once a response is sent, so this is safe to place in a
pipeline as well as behind `forward`.

## The gate

Documentation is rarely uniformly public. Internal runbooks, unreleased
features, and per-tenant guides all need someone to decide who may read
them — and that someone is the host, which knows about sessions, roles, and
tenancy. DocShell knows about none of it and should not pretend otherwise.

So authorization is a single `:gate` option, either a unary function or an
`{module, function, extra_args}` tuple receiving the conn first:

    init_opts: [gate: {MyApp.Auth, :allow_docs?, [:internal]}]

Return `:ok` or `true` to allow the request; anything else yields 403.
Omitting `:gate` serves every artifact to every caller, which is the right
default for genuinely public documentation and the wrong one everywhere
else — decide deliberately.

## Responses

  * `200` with `application/json` — the enveloped artifact
  * `403` — the gate refused
  * `404` — no such artifact, or a path that is not a single segment
  * `304` — the authorized request matches the artifact ETag
  * `405` — the method is neither GET nor HEAD

Multi-segment paths are rejected rather than joined, so no request can walk
out of the cache and into the filesystem.

## Multiple caches

The `:cache` option selects which named `DocShell.Web.Cache` to read,
defaulting to `DocShell.Web.Cache` itself. A host serving public and
internal artifact sets runs two caches and mounts this plug twice, with a
different gate on each.

Hosts that would rather route through their own controller can call
`DocShell.Web.Controller.show/2` instead. This module is only compiled when
Plug is installed.

---

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