# Server-side rendering

Source: https://apigenie.pl/docs/reference/doc-components/server-side-rendering
Part of the reference of [@mykulyak/apigenie-docs](https://apigenie.pl/docs/reference/doc-components.md).
Its other pages: [apg-api-reference and apg-spec](https://apigenie.pl/docs/reference/doc-components/reference-and-spec.md), [OpenAPI elements](https://apigenie.pl/docs/reference/doc-components/openapi.md), [Swagger 2.0 elements](https://apigenie.pl/docs/reference/doc-components/swagger.md), [AsyncAPI elements](https://apigenie.pl/docs/reference/doc-components/asyncapi.md), [Protobuf and gRPC elements](https://apigenie.pl/docs/reference/doc-components/protobuf.md), [GraphQL elements](https://apigenie.pl/docs/reference/doc-components/graphql.md), [Building blocks](https://apigenie.pl/docs/reference/doc-components/building-blocks.md), [Try it out](https://apigenie.pl/docs/reference/doc-components/try-it-out.md), [Theming](https://apigenie.pl/docs/reference/doc-components/theming.md), [apigenie-docs build](https://apigenie.pl/docs/reference/doc-components/docs-build.md).

`@mykulyak/apigenie-docs/ssr` renders the elements in Node with `@lit-labs/ssr` into declarative
shadow DOM: the documentation is HTML that search engines index and readers see before any script
runs. The `hydrate` entry point then makes it interactive without rendering it again.

```js
import { renderApiReference, preloadSpecAsync, pathToRoute, seoMeta, seoHead } from "@mykulyak/apigenie-docs/ssr";

const context = await preloadSpecAsync("/openapi.yaml", yamlText);
const html = await renderApiReference({ specUrl: "/openapi.yaml", route: "operation/getPet", routing: "history", basePath: "/docs" });
const head = seoHead(seoMeta(context, pathToRoute("operation/getPet"), "/docs"), "https://example.com");
// The page: <head>${head}</head>
// <body>${html}<script type="module" src="…/apigenie-web-components-hydrate.js"></script></body>
```

| Function | |
| --- | --- |
| `renderApiReference(options)` | Renders `<apg-api-reference>` on the page `route`. With `spec`, it reads that document first; without it, it renders the document preloaded for `specUrl`. It throws when no document is preloaded for `specUrl` or the document cannot be read. |
| `preloadSpec(url, document, format?, extras?)` | Reads a document for the elements naming `url` in `spec-url`, and returns its context. OpenAPI and Swagger 2.0 text or values and documentation models are read at once. AsyncAPI documents, `.proto` and GraphQL text are read in the background; preload them with `preloadSpecAsync` before rendering. |
| `preloadSpecAsync(url, document, format?, extras?)` | The same, resolving once AsyncAPI documents, `.proto` and GraphQL text are read with the configured module. |
| `preloadedSpec(url)` | The context preloaded for `url`, if any. |
| `clearSpecRegistry()` | Forgets every preloaded document, between two renders of different sites. |
| `renderToString(template, renderInfo?)` | Renders a page of parts after `preloadSpec`, each part naming the document in `spec-url`. |
| `routes(context)` | Every page of the reference, for a sitemap; the changelog page included when the context has one. |
| `routeToPath(route)`, `pathToRoute(path)` | The path of a page, and the page of a path. |
| `seoMeta(context, route, basePath?)` | The title, description and path of a page. |
| `seoHead(meta, origin?, alternates?)` | The `<head>` HTML of a page: title, description, the canonical link when `origin` is given, and the `hreflang` alternates. |
| `specScript(context)` | The document as `<script type="application/json" data-apg-spec>`, which `renderApiReference` embeds. |
| `docsScript(context)` | The extras of a docs bundle, as `<script data-apg-docs>`. |
| `configureAsyncApiEngine(url)`, `configureProtobufEngine(url)`, `configureGraphQLEngine(url)` | Set the WebAssembly module that reads the documents of each standard. |

## Options of `renderApiReference`

| Option | |
| --- | --- |
| `specUrl` | The key of the document; the elements of the page use it as `spec-url`. Required. |
| `spec` | The document as text or a value. Left out, the document preloaded for `specUrl` is rendered. |
| `route` | The page, such as `operation/getPet`; by default the overview. |
| `routing`, `basePath`, `layout`, `theme` | As the attributes of `<apg-api-reference>`. |
| `proxyUrl`, `oauth2RedirectUrl` | As `proxy-url` and `oauth2-redirect-url`. |
| `hideTryIt`, `hideSchemas`, `showProblems` | As `hide-try-it`, `hide-schemas` and `show-problems`. |
| `embedDocument` | Write the `<script data-apg-spec>` with the document; `true` by default. |

## The embedded document

The rendered markup embeds the document as `<script type="application/json" data-apg-spec>`, so
the browser uses what the server rendered instead of fetching the document again. For an AsyncAPI
document, a Protobuf file or a GraphQL schema it embeds the documentation model, which the browser
reads without the module.

AsyncAPI documents, as text or values, need the module on the server too: call
`configureAsyncApiEngine(url)` with the Node build (`asyncapi.mjs`, as a `file:` URL), then pass
the document to `renderApiReference` or `preloadSpecAsync`. After `preloadSpec` it is not read yet. `.proto` text likewise needs
`configureProtobufEngine` and `protobuf.mjs`, and GraphQL text `configureGraphQLEngine` and
`graphql.mjs`. Their documentation models, which a docs bundle holds, are read without a module.
