forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Core] [UA] Support API Deprecations (elastic#196081)
# Summary Adds a new API deprecations feature inside core. This feature enabled plugin developers to mark their versioned and unversioned public routes as deprecated. These deprecations will be surfaced to the users through UA to help them understand the deprecation and address it before upgrading. This PR also surfaces these deprecations to UA. Closes elastic#117241 1. Core service to flag deprecated routes 2. UA code to surface and resolve deprecated routes ## Flagging a deprecated Route ### The route deprecation option We have three types of route deprecations: - `type: bump`: A version bump deprecation means the API has a new version and the current version will be removed in the future in favor of the newer version. - `type: remove`: This API will be completely removed. You will no longer be able to use it in the future. - `type: migrate`: This API will be migrated to a different API and will be removed in the future in favor of the other API. All route deprecations expect a documentation link to help users navigate. We might add a generic documentation link and drop this requirement in the future but for now this is required. ### Deprecated Route Example Full examples can be found in the `routing_example` example plugin located in this directory: `examples/routing_example/server/routes/deprecated_routes` ```ts router[versioned?].get( { path: '/', options: { deprecated: { documentationUrl: 'https://google.com', severity: 'warning', reason: { type: 'bump', newApiVersion: '2024-10-13', }, }, }, }, async (context, req, res) => { ... ``` ## Surfaced API deprecations in UA The list of deprecated APIs will be listed inside Kibana deprecations along with the already supported config deprecations. <img width="1728" alt="image" src="https://github.com/user-attachments/assets/5bece704-b80b-4397-8ba2-6235f8995e4a"> Users can click on the list item to learn more about each deprecation and mark it as resolved <img width="1476" alt="image" src="https://github.com/user-attachments/assets/91c9207b-b246-482d-a5e4-21d0c61582a8"> ### Marking as resolved Users can click on mark as resolved button in the UA to hide the deprecation from the Kiban deprecations list. We keep track on when this button was clicked and how many times the API has been called. If the API is called again the deprecation will re-appear inside the list. We might add a feature in the future to permenantly supress the API deprecation from showing in the list through a configuration (elastic#196089) If the API has been marked as resolved before we show this in the flyout message: > The API GET /api/deprecations/ has been called 25 times. The last time the API was called was on Monday, October 14, 2024 1:08 PM +03:00. > The api has been called 2 times since the last time it was marked as resolved on Monday, October 14, 2024 1:08 PM +03:00 Once marked as resolved the flyout exists and we show this to the user until they refresh the page <img width="1453" alt="image" src="https://github.com/user-attachments/assets/8bb5bc8b-d1a3-478f-9489-23cfa7db6350"> ## Telemetry: We keep track of 2 new things for telemetry purposes: 1. The number of times the deprecated API has been called 2. The number of times the deprecated API has been resolved (how many times the mark as resolved button in UA was clicked) ## Code review - [x] Core team is expected to review the whole PR - [ ] Docs team to review the copy and update the UA displayed texts (title, description, and manual steps) - [x] kibana-management team is expected to review the UA code changes and UI - [ ] A few teams are only required to approve this PR and update their `deprecated: true` route param to the new deprecationInfo object we now expect. There is an issue tracker to address those in separate PRs later on: elastic#196095 ## Testing Run kibana locally with the test example plugin that has deprecated routes ``` yarn start --plugin-path=examples/routing_example --plugin-path=examples/developer_examples ``` The following comprehensive deprecated routes examples are registered inside the folder: `examples/routing_example/server/routes/deprecated_routes` Run them in the console to trigger the deprecation condition so they show up in the UA: ``` # Versioned routes: Version 1 is deprecated GET kbn:/api/routing_example/d/versioned?apiVersion=1 GET kbn:/api/routing_example/d/versioned?apiVersion=2 # Non-versioned routes GET kbn:/api/routing_example/d/removed_route POST kbn:/api/routing_example/d/migrated_route {} ``` 1. You can also mark as deprecated in the UA to remove the deprecation from the list. 2. Check the telemetry response to see the reported data about the deprecated route. 3. Calling version 2 of the API does not do anything since it is not deprecated unlike version `1` (`GET kbn:/api/routing_example/d/versioned?apiVersion=2`) 4. Internally you can see the deprecations counters from the dev console by running the following: ``` GET .kibana_usage_counters/_search { "query": { "bool": { "should": [ {"match": { "usage-counter.counterType": "deprecated_api_call:total"}}, {"match": { "usage-counter.counterType": "deprecated_api_call:resolved"}}, {"match": { "usage-counter.counterType": "deprecated_api_call:marked_as_resolved"}} ] } } } ``` --------- Co-authored-by: kibanamachine <[email protected]> Co-authored-by: florent-leborgne <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
- Loading branch information
1 parent
1e05086
commit c417196
Showing
139 changed files
with
2,057 additions
and
381 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
examples/routing_example/server/routes/deprecated_routes/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the "Elastic License | ||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side | ||
* Public License v 1"; you may not use this file except in compliance with, at | ||
* your election, the "Elastic License 2.0", the "GNU Affero General Public | ||
* License v3.0 only", or the "Server Side Public License, v 1". | ||
*/ | ||
|
||
import { IRouter } from '@kbn/core/server'; | ||
import { registerDeprecatedRoute } from './unversioned'; | ||
import { registerVersionedDeprecatedRoute } from './versioned'; | ||
|
||
export function registerDeprecatedRoutes(router: IRouter) { | ||
registerDeprecatedRoute(router); | ||
registerVersionedDeprecatedRoute(router); | ||
} |
62 changes: 62 additions & 0 deletions
62
examples/routing_example/server/routes/deprecated_routes/unversioned.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the "Elastic License | ||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side | ||
* Public License v 1"; you may not use this file except in compliance with, at | ||
* your election, the "Elastic License 2.0", the "GNU Affero General Public | ||
* License v3.0 only", or the "Server Side Public License, v 1". | ||
*/ | ||
|
||
import type { IRouter } from '@kbn/core/server'; | ||
import { schema } from '@kbn/config-schema'; | ||
import { DEPRECATED_ROUTES } from '../../../common'; | ||
|
||
export const registerDeprecatedRoute = (router: IRouter) => { | ||
router.get( | ||
{ | ||
path: DEPRECATED_ROUTES.REMOVED_ROUTE, | ||
validate: false, | ||
options: { | ||
access: 'public', | ||
deprecated: { | ||
documentationUrl: 'https://elastic.co/', | ||
severity: 'critical', | ||
reason: { type: 'remove' }, | ||
}, | ||
}, | ||
}, | ||
async (ctx, req, res) => { | ||
return res.ok({ | ||
body: { result: 'Called deprecated route. Check UA to see the deprecation.' }, | ||
}); | ||
} | ||
); | ||
|
||
router.post( | ||
{ | ||
path: DEPRECATED_ROUTES.MIGRATED_ROUTE, | ||
validate: { | ||
body: schema.object({ | ||
test: schema.maybe(schema.boolean()), | ||
}), | ||
}, | ||
options: { | ||
access: 'public', | ||
deprecated: { | ||
documentationUrl: 'https://elastic.co/', | ||
severity: 'critical', | ||
reason: { | ||
type: 'migrate', | ||
newApiMethod: 'GET', | ||
newApiPath: `${DEPRECATED_ROUTES.VERSIONED_ROUTE}?apiVersion=2`, | ||
}, | ||
}, | ||
}, | ||
}, | ||
async (ctx, req, res) => { | ||
return res.ok({ | ||
body: { result: 'Called deprecated route. Check UA to see the deprecation.' }, | ||
}); | ||
} | ||
); | ||
}; |
53 changes: 53 additions & 0 deletions
53
examples/routing_example/server/routes/deprecated_routes/versioned.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the "Elastic License | ||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side | ||
* Public License v 1"; you may not use this file except in compliance with, at | ||
* your election, the "Elastic License 2.0", the "GNU Affero General Public | ||
* License v3.0 only", or the "Server Side Public License, v 1". | ||
*/ | ||
|
||
import type { RequestHandler } from '@kbn/core-http-server'; | ||
import type { IRouter } from '@kbn/core/server'; | ||
import { DEPRECATED_ROUTES } from '../../../common'; | ||
|
||
const createDummyHandler = | ||
(version: string): RequestHandler => | ||
(ctx, req, res) => { | ||
return res.ok({ body: { result: `API version ${version}.` } }); | ||
}; | ||
|
||
export const registerVersionedDeprecatedRoute = (router: IRouter) => { | ||
const versionedRoute = router.versioned.get({ | ||
path: DEPRECATED_ROUTES.VERSIONED_ROUTE, | ||
description: 'Routing example plugin deprecated versioned route.', | ||
access: 'internal', | ||
options: { | ||
excludeFromOAS: true, | ||
}, | ||
enableQueryVersion: true, | ||
}); | ||
|
||
versionedRoute.addVersion( | ||
{ | ||
options: { | ||
deprecated: { | ||
documentationUrl: 'https://elastic.co/', | ||
severity: 'warning', | ||
reason: { type: 'bump', newApiVersion: '2' }, | ||
}, | ||
}, | ||
validate: false, | ||
version: '1', | ||
}, | ||
createDummyHandler('1') | ||
); | ||
|
||
versionedRoute.addVersion( | ||
{ | ||
version: '2', | ||
validate: false, | ||
}, | ||
createDummyHandler('2') | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.