Change the response status of metadata endpoints in case a documentation is not available to 404 NOT FOUND

Signed-off-by: Oliver Sand <oliver.sand@sda-se.com>
This commit is contained in:
Oliver Sand
2021-04-07 16:52:15 +02:00
parent 4c42dc291c
commit cba5944fcd
4 changed files with 28 additions and 73 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-techdocs-backend': patch
---
Change the response status of metadata endpoints in case a documentation is not
available to `404 NOT FOUND`. This also introduces the JSON based error messages
used by other backends.
@@ -1,26 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { getEntityNameFromUrlPath } from './helpers';
describe('getEntityNameFromUrlPath', () => {
it('should parse correctly', () => {
const path = 'default/Component/documented-component';
const parsedEntity = getEntityNameFromUrlPath(path);
expect(parsedEntity).toHaveProperty('namespace', 'default');
expect(parsedEntity).toHaveProperty('kind', 'Component');
expect(parsedEntity).toHaveProperty('name', 'documented-component');
});
});
@@ -1,30 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { EntityName } from '@backstage/catalog-model';
/**
* Using the path of the TechDocs page URL, return a structured EntityName type object with namespace,
* kind and name of the Entity.
* @param {string} path Example: default/Component/documented-component
*/
export const getEntityNameFromUrlPath = (path: string): EntityName => {
const [namespace, kind, name] = path.split('/');
return {
namespace,
kind,
name,
};
};
+21 -17
View File
@@ -14,8 +14,9 @@
* limitations under the License.
*/
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { Entity } from '@backstage/catalog-model';
import { Entity, stringifyEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import { NotFoundError } from '@backstage/errors';
import {
GeneratorBuilder,
getLocationForEntity,
@@ -30,8 +31,6 @@ import { Knex } from 'knex';
import { Logger } from 'winston';
import { DocsBuilder } from '../DocsBuilder';
import { shouldCheckForUpdate } from '../DocsBuilder/BuildMetadataStorage';
import { getEntityNameFromUrlPath } from './helpers';
import { NotFoundError } from '@backstage/errors';
type RouterOptions = {
preparers: PreparerBuilder;
@@ -55,10 +54,9 @@ export async function createRouter({
}: RouterOptions): Promise<express.Router> {
const router = Router();
router.get('/metadata/techdocs/*', async (req, res) => {
// path is `:namespace/:kind:/:name`
const { '0': path } = req.params;
const entityName = getEntityNameFromUrlPath(path);
router.get('/metadata/techdocs/:namespace/:kind/:name', async (req, res) => {
const { kind, namespace, name } = req.params;
const entityName = { kind, namespace, name };
try {
const techdocsMetadata = await publisher.fetchTechDocsMetadata(
@@ -67,14 +65,15 @@ export async function createRouter({
res.json(techdocsMetadata);
} catch (err) {
logger.error(
`Unable to get metadata for ${entityName.namespace}/${entityName.name} with error ${err}`,
logger.info(
`Unable to get metadata for '${stringifyEntityRef(
entityName,
)}' with error ${err}`,
);
throw new NotFoundError(
`Unable to get metadata for '${stringifyEntityRef(entityName)}'`,
err,
);
res
.status(500)
.send(
`Unable to get metadata for $${entityName.namespace}/${entityName.name}, reason: ${err}`,
);
}
});
@@ -82,9 +81,11 @@ export async function createRouter({
const catalogUrl = await discovery.getBaseUrl('catalog');
const { kind, namespace, name } = req.params;
const entityName = { kind, namespace, name };
try {
const token = getBearerToken(req.headers.authorization);
// TODO: Consider using the catalog client here
const entity = (await (
await fetch(
`${catalogUrl}/entities/by-name/${kind}/${namespace}/${name}`,
@@ -98,10 +99,13 @@ export async function createRouter({
res.json({ ...entity, locationMetadata });
} catch (err) {
logger.info(
`Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`,
`Unable to get metadata for '${stringifyEntityRef(
entityName,
)}' with error ${err}`,
);
throw new Error(
`Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`,
throw new NotFoundError(
`Unable to get metadata for '${stringifyEntityRef(entityName)}'`,
err,
);
}
});