[Docs] Added OAS dev tutorial (#187573)

## Summary

<details>

<summary>Screenshot (slightly outdated)</summary>



![localhost_3000_kibana-dev-docs_genereating-oas-for-http-apis](29cf0aff-e150-4e4c-ab47-d7b7bad60141)


</detials>
This commit is contained in:
Jean-Louis Leysens 2024-07-05 10:47:14 +02:00 committed by GitHub
parent 3a9b01cf22
commit 9575b3a17e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 188 additions and 4 deletions

View file

@ -0,0 +1,178 @@
---
id: kibDevTutorialGeneratingOASForHTTPAPIs
slug: /kibana-dev-docs/genereating-oas-for-http-apis
title: Generating OAS for HTTP APIs
description: This tutorial demonstrates how to generate OpenAPI specification for HTTP APIs.
date: 2024-07-04
tags: ['kibana', 'onboarding', 'dev', 'architecture', 'http', 'rest', 'api']
---
<DocCallOut title="OAS is required for all public routes">
If your route declares `access: 'public'` you **must** provide up-to-date OpenAPI specification for it. Docs for these routes get hosted on [on our docs site](https://www.elastic.co/docs/api/doc/serverless) and are used for client integrations. For example: our [Elastic stack terraform provider](https://github.com/elastic/terraform-provider-elasticstack).
</DocCallOut>
### Important components
To get OAS generated for HTTP APIs you must use the following components:
1. Core's `router` or `router.versioned` for defining HTTP APIs provided via the `core.http` service to all plugins
2. `@kbn/config-schema` request and response schemas, skip to <a href="#what-about-runtime-validation-libary-x">this</a> FAQ for more information
<DocCallOut title="Beyond runtime validation">
Kibana's core platform supports `@kbn/config-schema` as a first-class citizen for various schema purposes: configuration, saved objects, and HTTP API request/response bodies.
Developers can leverage `@kbn/config-schema` as a single-source of truth for runtime validation, TypeScript interfaces, and OpenAPI specification.
</DocCallOut>
### How do I see my HTTP API's OAS?
In `kibana.dev.yml` add the following configuration:
```yaml
server.oas.enabled: true
```
Launch Kibana and send the following request:
```bash
curl -s -uelastic:changeme http://localhost:5601/api/oas\?pathStartsWith\=/api/foo
```
The value returned should contain the OpenAPI specification for your route and any other path's start with `/api/foo`.
Other useful query parameters for filtering are:
* `pluginId` - get the OAS for a specific plugin, for example: `@kbn/data-views-plugin`
* `access` - filter for specific access levels: `public` or `internal` are supported
### Some good practices to consider
#### 1. Runtime schema definitions
```typescript
// In server/schemas/v1.ts
import { schema, TypeOf } from '@kbn/config-schema';
export const fooResource = schema.object({
name: schema.string()
// ...and any other fields you may need
});
export type FooResource = TypeOf<typeof fooResource>;
// In common/foo/v1.ts
export type { FooResource } from '../server/schemas/v1';
// In common/index.ts expose this as the "latest" schema shape
export type { FooResource } from './latest';
export * as fooResourceV1 from '../foo/v1';
```
This example demonstrates how you can organize runtime schemas to prepare for:
1. Being versioned
2. Have TypeScript references available to client and server code in your plugin
See <DocLink id="kibDevTutorialVersioningInterfaces" text="strategies for versioning your schemas" /> for more information on this organizational pattern.
#### 2. Route definitions
```typescript
// Somewhere in your plugin's server/routes folder
import { schema, TypeOf } from '@kbn/config-schema';
import type { FooResource } from '../../../common';
import { fooResource } from '../../schemas/v1';
// Note: this response schema is instantiated lazily to avoid creating schemas that are not needed in most cases!
const fooResourceResponse = () => {
return schema.object({
id: schema.string({ maxLength: 20 }),
name: schema.string(),
createdAt: schema.string(),
})
}
// Note: TypeOf can extract types for lazily instantiated schemas
type FooResourceResponse = TypeOf<typeof fooResourceResponse>
function registerFooRoute(router: IRouter, docLinks: DoclinksStart) {
router.versioned
.post({
path: '/api/foo',
access: 'public',
summary: 'Create a foo resource'
description: `A foo resource enables baz. See the following [documentation](${docLinks.links.fooResource}).`,
})
.addVersion({
version: '2023-10-31',
validate: {
request: {
body: ,
},
response: {
200: {
body: fooResourceResponse,
},
},
},
},
async (ctx, req, res) => {
const core = await ctx.core;
const savedObjectsClient = core.savedObjects.client;
const body = req.body;
const foo = await createFoo({ name: body.name });
// This is our HTTP translation layer to ensure only the necessary fields included
const responseBody: FooResourceResponse = {
id: foo.id,
name: foo.name,
createdAt: foo.createdAt,
};
return res.ok({ body: responseBody });
}
);
}
```
#### 3. Generating OAS
See <a href="#how-do-i-see-my-http-apis-oas">this section</a> about viewing your HTTP APIs OAS.
#### 4. Iterating on OAS
From here, you can develop your route and schema definitions iteratively. After each change the Kibana server will
automatically reload and the latest OAS should reflect the current state of your code!
For example, let's add a few descriptions to our schema members:
```typescript
const fooResourceResponse = () => {
return schema.object({
id: schema.string({ maxLength: 20, meta: { description: 'An unique ID for a foo resource.'} }),
name: schema.string({ meta: { description: 'A human friendly name for a foo resource.'} }),
createdAt: schema.string({ meta: { description: 'The ISO date a foo resource was created.'} }),
})
}
```
This descriptions should now be reflected in the OAS generated for your route.
#### 5. Publishing OAS
OAS for public routes are written to the Kibana repo as a snapshot that will ultimately be published.
<DocCallOut title="Under construction" color="warning">
At the time of writing we only capture OAS for a subset of Kibana's HTTP APIs to give teams time to check and improve the quality of generated OAS.
If you would like OAS for your endpoints to be included in the snapshot, **please reach out to #kibana-core**.
</DocCallOut>
### FAQs
#### What about runtime validation libary X?
Teams have adopted different runtime validation libraries for their HTTP APIs. Kibana core does not intend to support all runtime validation libraries.
Reach out to #kibana-core with questions, concerns or issues you may be facing with `@kbn/config-schema` and we will help you find a solution.
#### What about internal HTTP APIs?
It's possible to generate OpenAPI specification for `access: 'internal'` routes but it is not required. The benefit will largely be for your team's internal reference and for other teams to discover your APIs. If you follow the practices outlined in this tutorial it should be simple to generate OAS for internal routes as well.

View file

@ -3,7 +3,7 @@ id: kibDevTutorialVersioningHTTPAPIs
slug: /kibana-dev-docs/versioning-http-apis
title: Versioning HTTP APIs
description: This tutorial demonstrates how to create or migrate to versionable HTTP APIs.
date: 2023-02-09
date: 2024-07-04
tags: ['kibana', 'onboarding', 'dev', 'architecture']
---

View file

@ -135,6 +135,9 @@
"id": "kibDevTutorialVersioningInterfaces",
"label": "Versioning interfaces"
},
{
"id": "kibDevTutorialGeneratingOASForHTTPAPIs"
},
{
"id": "kibDevTutorialSubmitPullRequest"
},

View file

@ -88,9 +88,12 @@ module.exports = {
],
"nav": {
"structure": [
"nav-elastic-developer-guide",
"nav-kibana-team",
"nav-kibana-dev"
{
collection: 'Elastic Developer Guide',
navs: ['nav-elastic-developer-guide'],
},
{ collection: 'Kibana Team', navs: ['nav-kibana-team'] },
{ collection: 'Kibana Developer Guide', navs: ['nav-kibana-dev'] },
],
"default": "nav-kibana-dev"
}