Stop special-casing component, call things 'entity' everywhere
This commit is contained in:
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
DatabaseItemsCatalog,
|
||||
createRouter,
|
||||
DatabaseEntitiesCatalog,
|
||||
DatabaseLocationsCatalog,
|
||||
DatabaseManager,
|
||||
createRouter,
|
||||
runPeriodically,
|
||||
LocationReaders,
|
||||
DescriptorParsers,
|
||||
LocationReaders,
|
||||
runPeriodically,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
@@ -35,8 +35,8 @@ export default async function ({ logger, database }: PluginEnvironment) {
|
||||
10000,
|
||||
);
|
||||
|
||||
const itemsCatalog = new DatabaseItemsCatalog(db);
|
||||
const entitiesCatalog = new DatabaseEntitiesCatalog(db);
|
||||
const locationsCatalog = new DatabaseLocationsCatalog(db);
|
||||
|
||||
return await createRouter({ itemsCatalog, locationsCatalog, logger });
|
||||
return await createRouter({ entitiesCatalog, locationsCatalog, logger });
|
||||
}
|
||||
|
||||
+6
-6
@@ -15,18 +15,18 @@
|
||||
*/
|
||||
|
||||
import { Database } from '../database';
|
||||
import { Component, ItemsCatalog } from './types';
|
||||
import { EntitiesCatalog, Entity } from './types';
|
||||
|
||||
export class DatabaseItemsCatalog implements ItemsCatalog {
|
||||
export class DatabaseEntitiesCatalog implements EntitiesCatalog {
|
||||
constructor(private readonly database: Database) {}
|
||||
|
||||
async components(): Promise<Component[]> {
|
||||
const items = await this.database.components();
|
||||
async entities(): Promise<Entity[]> {
|
||||
const items = await this.database.entities();
|
||||
return items;
|
||||
}
|
||||
|
||||
async component(name: string): Promise<Component> {
|
||||
const item = await this.database.component(name);
|
||||
async entity(name: string): Promise<Entity> {
|
||||
const item = await this.database.entity(name);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -15,23 +15,23 @@
|
||||
*/
|
||||
|
||||
import { NotFoundError } from '@backstage/backend-common';
|
||||
import { Component, ItemsCatalog } from './types';
|
||||
import { EntitiesCatalog, Entity } from './types';
|
||||
|
||||
export class StaticItemsCatalog implements ItemsCatalog {
|
||||
private _components: Component[];
|
||||
export class StaticEntitiesCatalog implements EntitiesCatalog {
|
||||
private _entities: Entity[];
|
||||
|
||||
constructor(components: Component[]) {
|
||||
this._components = components;
|
||||
constructor(entities: Entity[]) {
|
||||
this._entities = entities;
|
||||
}
|
||||
|
||||
async components(): Promise<Component[]> {
|
||||
return this._components.slice();
|
||||
async entities(): Promise<Entity[]> {
|
||||
return this._entities.slice();
|
||||
}
|
||||
|
||||
async component(name: string): Promise<Component> {
|
||||
const item = this._components.find(i => i.name === name);
|
||||
async entity(name: string): Promise<Entity> {
|
||||
const item = this._entities.find(e => e.name === name);
|
||||
if (!item) {
|
||||
throw new NotFoundError(`Found no component with name ${name}`);
|
||||
throw new NotFoundError(`Found no entity with name ${name}`);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './DatabaseItemsCatalog';
|
||||
export * from './DatabaseEntitiesCatalog';
|
||||
export * from './DatabaseLocationsCatalog';
|
||||
export * from './StaticItemsCatalog';
|
||||
export * from './StaticEntitiesCatalog';
|
||||
export * from './types';
|
||||
|
||||
@@ -20,15 +20,15 @@ import * as yup from 'yup';
|
||||
// Items
|
||||
//
|
||||
|
||||
export type Component = {
|
||||
export type Entity = {
|
||||
id: string;
|
||||
locationId?: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type ItemsCatalog = {
|
||||
components(): Promise<Component[]>;
|
||||
component(id: string): Promise<Component>;
|
||||
export type EntitiesCatalog = {
|
||||
entities(): Promise<Entity[]>;
|
||||
entity(id: string): Promise<Entity>;
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { NotFoundError } from '@backstage/backend-common';
|
||||
import Knex from 'knex';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { NotFoundError } from '@backstage/backend-common';
|
||||
import {
|
||||
AddDatabaseComponent,
|
||||
AddDatabaseEntity,
|
||||
AddDatabaseLocation,
|
||||
DatabaseComponent,
|
||||
DatabaseEntity,
|
||||
DatabaseLocation,
|
||||
DatabaseLocationUpdateLogEvent,
|
||||
DatabaseLocationUpdateLogStatus,
|
||||
@@ -29,34 +29,34 @@ import {
|
||||
export class Database {
|
||||
constructor(private readonly database: Knex) {}
|
||||
|
||||
async addOrUpdateComponent(component: AddDatabaseComponent): Promise<void> {
|
||||
async addOrUpdateEntity(entity: AddDatabaseEntity): Promise<void> {
|
||||
await this.database.transaction(async tx => {
|
||||
// TODO(freben): Currently, several locations can compete for the same component
|
||||
// TODO(freben): Currently, several locations can compete for the same entity
|
||||
// TODO(freben): If locationId is unset in the input, it won't be overwritten - should we instead replace with null?
|
||||
const count = await tx<DatabaseComponent>('components')
|
||||
.where({ name: component.name })
|
||||
.update({ ...component });
|
||||
const count = await tx<DatabaseEntity>('entities')
|
||||
.where({ name: entity.name })
|
||||
.update({ ...entity });
|
||||
if (!count) {
|
||||
await tx<DatabaseComponent>('components').insert({
|
||||
...component,
|
||||
await tx<DatabaseEntity>('entities').insert({
|
||||
...entity,
|
||||
id: uuidv4(),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async components(): Promise<DatabaseComponent[]> {
|
||||
return await this.database<DatabaseComponent>('components')
|
||||
async entities(): Promise<DatabaseEntity[]> {
|
||||
return await this.database<DatabaseEntity>('entities')
|
||||
.orderBy('name')
|
||||
.select();
|
||||
}
|
||||
|
||||
async component(name: string): Promise<DatabaseComponent> {
|
||||
const items = await this.database<DatabaseComponent>('components')
|
||||
async entity(name: string): Promise<DatabaseEntity> {
|
||||
const items = await this.database<DatabaseEntity>('entities')
|
||||
.where({ name })
|
||||
.select();
|
||||
if (!items.length) {
|
||||
throw new NotFoundError(`Found no component with name ${name}`);
|
||||
throw new NotFoundError(`Found no entity with name ${name}`);
|
||||
}
|
||||
return items[0];
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export class Database {
|
||||
async addLocationUpdateLogEvent(
|
||||
locationId: string,
|
||||
status: DatabaseLocationUpdateLogStatus,
|
||||
componentName?: string,
|
||||
entityName?: string,
|
||||
message?: string,
|
||||
): Promise<void> {
|
||||
return this.database<DatabaseLocationUpdateLogEvent>(
|
||||
@@ -123,7 +123,7 @@ export class Database {
|
||||
id: uuidv4(),
|
||||
status: status,
|
||||
location_id: locationId,
|
||||
component_name: componentName,
|
||||
entity_name: entityName,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('DatabaseManager', () => {
|
||||
describe('refreshLocations', () => {
|
||||
it('works with no locations added', async () => {
|
||||
const db = ({
|
||||
addOrUpdateComponent: jest.fn(),
|
||||
addOrUpdateEntity: jest.fn(),
|
||||
locations: jest.fn().mockResolvedValue([]),
|
||||
} as unknown) as Database;
|
||||
const reader: LocationReader = {
|
||||
@@ -53,7 +53,7 @@ describe('DatabaseManager', () => {
|
||||
|
||||
it('can update a single location', async () => {
|
||||
const db = ({
|
||||
addOrUpdateComponent: jest.fn(),
|
||||
addOrUpdateEntity: jest.fn(),
|
||||
locations: jest.fn(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
@@ -76,9 +76,7 @@ describe('DatabaseManager', () => {
|
||||
read: jest.fn(() => Promise.resolve([{ type: 'data', data: desc }])),
|
||||
};
|
||||
const parser: DescriptorParser = {
|
||||
parse: jest.fn(() =>
|
||||
Promise.resolve({ kind: 'Component', component: desc }),
|
||||
),
|
||||
parse: jest.fn(() => Promise.resolve(desc)),
|
||||
};
|
||||
|
||||
await expect(
|
||||
@@ -86,8 +84,8 @@ describe('DatabaseManager', () => {
|
||||
).resolves.toBeUndefined();
|
||||
expect(reader.read).toHaveBeenCalledTimes(1);
|
||||
expect(reader.read).toHaveBeenNthCalledWith(1, 'some', 'thing');
|
||||
expect(db.addOrUpdateComponent).toHaveBeenCalledTimes(1);
|
||||
expect(db.addOrUpdateComponent).toHaveBeenNthCalledWith(
|
||||
expect(db.addOrUpdateEntity).toHaveBeenCalledTimes(1);
|
||||
expect(db.addOrUpdateEntity).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ locationId: '123', name: 'c1' }),
|
||||
);
|
||||
@@ -95,7 +93,7 @@ describe('DatabaseManager', () => {
|
||||
|
||||
it('logs successful updates', async () => {
|
||||
const db = ({
|
||||
addOrUpdateComponent: jest.fn(),
|
||||
addOrUpdateEntity: jest.fn(),
|
||||
locations: jest.fn(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
@@ -118,9 +116,7 @@ describe('DatabaseManager', () => {
|
||||
read: jest.fn(() => Promise.resolve([{ type: 'data', data: desc }])),
|
||||
};
|
||||
const parser: DescriptorParser = {
|
||||
parse: jest.fn(() =>
|
||||
Promise.resolve({ kind: 'Component', component: desc }),
|
||||
),
|
||||
parse: jest.fn(() => Promise.resolve(desc)),
|
||||
};
|
||||
|
||||
await expect(
|
||||
@@ -144,7 +140,7 @@ describe('DatabaseManager', () => {
|
||||
|
||||
it('logs unsuccessful updates when parser fails', async () => {
|
||||
const db = ({
|
||||
addOrUpdateComponent: jest.fn(),
|
||||
addOrUpdateEntity: jest.fn(),
|
||||
locations: jest.fn(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
@@ -194,7 +190,7 @@ describe('DatabaseManager', () => {
|
||||
|
||||
it('logs unsuccessful updates when reader fails', async () => {
|
||||
const db = ({
|
||||
addOrUpdateComponent: jest.fn(),
|
||||
addOrUpdateEntity: jest.fn(),
|
||||
locations: jest.fn(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ import path from 'path';
|
||||
import { Logger } from 'winston';
|
||||
import { DescriptorParser, LocationReader, ParserError } from '../ingestion';
|
||||
import { Database } from './Database';
|
||||
import { AddDatabaseComponent, DatabaseLocationUpdateLogStatus } from './types';
|
||||
import { AddDatabaseEntity, DatabaseLocationUpdateLogStatus } from './types';
|
||||
|
||||
export class DatabaseManager {
|
||||
public static async createDatabase(database: Knex): Promise<Database> {
|
||||
@@ -33,12 +33,12 @@ export class DatabaseManager {
|
||||
private static async logUpdateSuccess(
|
||||
database: Database,
|
||||
locationId: string,
|
||||
componentName?: string,
|
||||
entityName?: string,
|
||||
) {
|
||||
return database.addLocationUpdateLogEvent(
|
||||
locationId,
|
||||
DatabaseLocationUpdateLogStatus.SUCCESS,
|
||||
componentName,
|
||||
entityName,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,12 +46,12 @@ export class DatabaseManager {
|
||||
database: Database,
|
||||
locationId: string,
|
||||
error?: Error,
|
||||
componentName?: string,
|
||||
entityName?: string,
|
||||
) {
|
||||
return database.addLocationUpdateLogEvent(
|
||||
locationId,
|
||||
DatabaseLocationUpdateLogStatus.FAIL,
|
||||
componentName,
|
||||
entityName,
|
||||
error?.message,
|
||||
);
|
||||
}
|
||||
@@ -76,32 +76,28 @@ export class DatabaseManager {
|
||||
logger.debug(readerItem.error);
|
||||
continue;
|
||||
}
|
||||
let parserOutput;
|
||||
try {
|
||||
parserOutput = await parser.parse(readerItem.data);
|
||||
if (parserOutput.kind === 'Component') {
|
||||
const component = parserOutput.component;
|
||||
const dbc: AddDatabaseComponent = {
|
||||
locationId: location.id,
|
||||
name: component.metadata.name,
|
||||
};
|
||||
await database.addOrUpdateComponent(dbc);
|
||||
await DatabaseManager.logUpdateSuccess(
|
||||
database,
|
||||
location.id,
|
||||
component.metadata.name,
|
||||
);
|
||||
}
|
||||
const entity = await parser.parse(readerItem.data);
|
||||
const dbc: AddDatabaseEntity = {
|
||||
locationId: location.id,
|
||||
name: entity.metadata!.name!,
|
||||
};
|
||||
await database.addOrUpdateEntity(dbc);
|
||||
await DatabaseManager.logUpdateSuccess(
|
||||
database,
|
||||
location.id,
|
||||
entity.metadata!.name,
|
||||
);
|
||||
} catch (error) {
|
||||
let componentName;
|
||||
let entityName;
|
||||
if (error instanceof ParserError) {
|
||||
componentName = error.componentName;
|
||||
entityName = error.entityName;
|
||||
}
|
||||
await DatabaseManager.logUpdateFailure(
|
||||
database,
|
||||
location.id,
|
||||
error,
|
||||
componentName,
|
||||
entityName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,23 +29,23 @@ export async function up(knex: Knex): Promise<any> {
|
||||
.notNullable()
|
||||
.comment('The actual target of the location');
|
||||
})
|
||||
.createTable('components', table => {
|
||||
table.comment('All components currently stored in the catalog');
|
||||
table.uuid('id').primary().comment('Auto-generated ID of the component');
|
||||
.createTable('entities', table => {
|
||||
table.comment('All entities currently stored in the catalog');
|
||||
table.uuid('id').primary().comment('Auto-generated ID of the entity');
|
||||
table
|
||||
.uuid('locationId')
|
||||
.references('id')
|
||||
.inTable('locations')
|
||||
.nullable()
|
||||
.comment('The location that originated the component');
|
||||
.comment('The location that originated the entity');
|
||||
table
|
||||
.string('name')
|
||||
.unique()
|
||||
.notNullable()
|
||||
.comment('The external name of the component, as used in references');
|
||||
.comment('The external name of the entity, as used in references');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<any> {
|
||||
return knex.schema.dropTable('components').dropTable('locations');
|
||||
return knex.schema.dropTable('entities').dropTable('locations');
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ export async function up(knex: Knex): Promise<any> {
|
||||
.inTable('locations')
|
||||
.onUpdate('CASCADE')
|
||||
.onDelete('CASCADE');
|
||||
table.string('component_name').notNullable();
|
||||
table.string('entity_name').notNullable();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,18 @@
|
||||
|
||||
import * as yup from 'yup';
|
||||
|
||||
export type DatabaseComponent = {
|
||||
export type DatabaseEntity = {
|
||||
id: string;
|
||||
locationId?: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type AddDatabaseComponent = {
|
||||
export type AddDatabaseEntity = {
|
||||
locationId?: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const addDatabaseComponentSchema: yup.Schema<AddDatabaseComponent> = yup
|
||||
export const addDatabaseEntitySchema: yup.Schema<AddDatabaseEntity> = yup
|
||||
.object({
|
||||
locationId: yup.string().optional(),
|
||||
name: yup.string().required(),
|
||||
@@ -61,7 +61,7 @@ export type DatabaseLocationUpdateLogEvent = {
|
||||
id: string;
|
||||
status: DatabaseLocationUpdateLogStatus;
|
||||
location_id: string;
|
||||
component_name: string;
|
||||
entity_name: string;
|
||||
created_at?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DescriptorEnvelopeParser } from './descriptors/DescriptorEnvelopeParser';
|
||||
import { ComponentDescriptorV1beta1Parser } from './descriptors/ComponentDescriptorV1beta1Parser';
|
||||
import { KindParser } from './descriptors/types';
|
||||
import { DescriptorParser, ParserError, ParserOutput } from './types';
|
||||
import { makeValidator } from '../validation';
|
||||
import { ComponentDescriptorV1beta1Parser } from './descriptors/ComponentDescriptorV1beta1Parser';
|
||||
import {
|
||||
DescriptorEnvelope,
|
||||
DescriptorEnvelopeParser,
|
||||
} from './descriptors/DescriptorEnvelopeParser';
|
||||
import { KindParser } from './descriptors/types';
|
||||
import { DescriptorParser, ParserError } from './types';
|
||||
|
||||
export class DescriptorParsers implements DescriptorParser {
|
||||
static create(): DescriptorParser {
|
||||
@@ -33,7 +36,7 @@ export class DescriptorParsers implements DescriptorParser {
|
||||
private readonly kindParsers: KindParser[],
|
||||
) {}
|
||||
|
||||
async parse(descriptor: object): Promise<ParserOutput> {
|
||||
async parse(descriptor: object): Promise<DescriptorEnvelope> {
|
||||
const envelope = await this.envelopeParser.parse(descriptor);
|
||||
for (const parser of this.kindParsers) {
|
||||
const parsed = await parser.tryParse(envelope);
|
||||
|
||||
+3
-6
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { ParserError, ParserOutput } from '../types';
|
||||
import { ParserError } from '../types';
|
||||
import { DescriptorEnvelope } from './DescriptorEnvelopeParser';
|
||||
import { KindParser } from './types';
|
||||
|
||||
@@ -48,7 +48,7 @@ export class ComponentDescriptorV1beta1Parser implements KindParser {
|
||||
|
||||
async tryParse(
|
||||
envelope: DescriptorEnvelope,
|
||||
): Promise<ParserOutput | undefined> {
|
||||
): Promise<DescriptorEnvelope | undefined> {
|
||||
if (
|
||||
envelope.apiVersion !== 'backstage.io/v1beta1' ||
|
||||
envelope.kind !== 'Component'
|
||||
@@ -57,10 +57,7 @@ export class ComponentDescriptorV1beta1Parser implements KindParser {
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
kind: 'Component',
|
||||
component: await this.schema.validate(envelope, { strict: true }),
|
||||
};
|
||||
return await this.schema.validate(envelope, { strict: true });
|
||||
} catch (e) {
|
||||
throw new ParserError(
|
||||
`Malformed component, ${e}`,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ParserOutput } from '../types';
|
||||
import { DescriptorEnvelope } from './DescriptorEnvelopeParser';
|
||||
|
||||
export type KindParser = {
|
||||
@@ -30,5 +29,7 @@ export type KindParser = {
|
||||
* @throws An Error if the type was handled and found to not be properly
|
||||
* formatted
|
||||
*/
|
||||
tryParse(envelope: DescriptorEnvelope): Promise<ParserOutput | undefined>;
|
||||
tryParse(
|
||||
envelope: DescriptorEnvelope,
|
||||
): Promise<DescriptorEnvelope | undefined>;
|
||||
};
|
||||
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
|
||||
import { ComponentDescriptorV1beta1 } from './descriptors/ComponentDescriptorV1beta1Parser';
|
||||
import { DescriptorEnvelope } from './descriptors/DescriptorEnvelopeParser';
|
||||
|
||||
export type ComponentDescriptor = ComponentDescriptorV1beta1;
|
||||
|
||||
export type ParserOutput = {
|
||||
kind: 'Component';
|
||||
component: ComponentDescriptor;
|
||||
};
|
||||
|
||||
export type DescriptorParser = {
|
||||
/**
|
||||
* Parses and validates a single raw descriptor.
|
||||
@@ -31,15 +27,15 @@ export type DescriptorParser = {
|
||||
* @returns A structure describing the parsed and validated descriptor
|
||||
* @throws An Error if the descriptor was malformed
|
||||
*/
|
||||
parse(descriptor: object): Promise<ParserOutput>;
|
||||
parse(descriptor: object): Promise<DescriptorEnvelope>;
|
||||
};
|
||||
|
||||
export class ParserError extends Error {
|
||||
constructor(message?: string, private _componentName?: string | undefined) {
|
||||
constructor(message?: string, private _entityName?: string | undefined) {
|
||||
super(message);
|
||||
}
|
||||
get componentName() {
|
||||
return this._componentName;
|
||||
get entityName() {
|
||||
return this._entityName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import { addLocationSchema, ItemsCatalog, LocationsCatalog } from '../catalog';
|
||||
import {
|
||||
addLocationSchema,
|
||||
EntitiesCatalog,
|
||||
LocationsCatalog,
|
||||
} from '../catalog';
|
||||
import { validateRequestBody } from './util';
|
||||
|
||||
export interface RouterOptions {
|
||||
itemsCatalog?: ItemsCatalog;
|
||||
entitiesCatalog?: EntitiesCatalog;
|
||||
locationsCatalog?: LocationsCatalog;
|
||||
logger: Logger;
|
||||
}
|
||||
@@ -29,21 +33,20 @@ export interface RouterOptions {
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const { itemsCatalog, locationsCatalog } = options;
|
||||
const logger = options.logger.child({ plugin: 'catalog' });
|
||||
const { entitiesCatalog, locationsCatalog } = options;
|
||||
const router = Router();
|
||||
|
||||
if (itemsCatalog) {
|
||||
// Components
|
||||
if (entitiesCatalog) {
|
||||
// Entities
|
||||
router
|
||||
.get('/components', async (_req, res) => {
|
||||
const components = await itemsCatalog.components();
|
||||
res.status(200).send(components);
|
||||
.get('/entities', async (_req, res) => {
|
||||
const entities = await entitiesCatalog.entities();
|
||||
res.status(200).send(entities);
|
||||
})
|
||||
.get('/components/:id', async (req, res) => {
|
||||
.get('/entities/:id', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const component = await itemsCatalog.component(id);
|
||||
res.status(200).send(component);
|
||||
const entity = await entitiesCatalog.entity(id);
|
||||
res.status(200).send(entity);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,9 +74,5 @@ export async function createRouter(
|
||||
});
|
||||
}
|
||||
|
||||
const app = express();
|
||||
app.set('logger', logger);
|
||||
app.use('/', router);
|
||||
|
||||
return app;
|
||||
return router;
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ import cors from 'cors';
|
||||
import express from 'express';
|
||||
import helmet from 'helmet';
|
||||
import { Logger } from 'winston';
|
||||
import { ItemsCatalog, LocationsCatalog } from '../catalog';
|
||||
import { EntitiesCatalog, LocationsCatalog } from '../catalog';
|
||||
import { createRouter } from './router';
|
||||
|
||||
export interface ApplicationOptions {
|
||||
enableCors: boolean;
|
||||
itemsCatalog: ItemsCatalog;
|
||||
entitiesCatalog: EntitiesCatalog;
|
||||
locationsCatalog?: LocationsCatalog;
|
||||
logger: Logger;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ export interface ApplicationOptions {
|
||||
export async function createStandaloneApplication(
|
||||
options: ApplicationOptions,
|
||||
): Promise<express.Application> {
|
||||
const { enableCors, itemsCatalog, locationsCatalog, logger } = options;
|
||||
const { enableCors, entitiesCatalog, locationsCatalog, logger } = options;
|
||||
const app = express();
|
||||
|
||||
app.use(helmet());
|
||||
@@ -47,7 +47,10 @@ export async function createStandaloneApplication(
|
||||
app.use(compression());
|
||||
app.use(express.json());
|
||||
app.use(requestLoggingHandler());
|
||||
app.use('/', await createRouter({ itemsCatalog, locationsCatalog, logger }));
|
||||
app.use(
|
||||
'/',
|
||||
await createRouter({ entitiesCatalog, locationsCatalog, logger }),
|
||||
);
|
||||
app.use(notFoundHandler());
|
||||
app.use(errorHandler());
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { Server } from 'http';
|
||||
import { Logger } from 'winston';
|
||||
import { StaticItemsCatalog } from '../catalog';
|
||||
import { StaticEntitiesCatalog } from '../catalog';
|
||||
import { createStandaloneApplication } from './standaloneApplication';
|
||||
|
||||
export interface ServerOptions {
|
||||
@@ -30,15 +30,15 @@ export async function startStandaloneServer(
|
||||
): Promise<Server> {
|
||||
const logger = options.logger.child({ service: 'catalog-backend' });
|
||||
|
||||
const itemsCatalog = new StaticItemsCatalog([
|
||||
{ id: '1', name: 'component1' },
|
||||
{ id: '2', name: 'component2' },
|
||||
const entitiesCatalog = new StaticEntitiesCatalog([
|
||||
{ id: '1', name: 'entity1' },
|
||||
{ id: '2', name: 'entity2' },
|
||||
]);
|
||||
|
||||
logger.debug('Creating application...');
|
||||
const app = await createStandaloneApplication({
|
||||
enableCors: options.enableCors,
|
||||
itemsCatalog,
|
||||
entitiesCatalog,
|
||||
logger,
|
||||
});
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Validators } from './types';
|
||||
import { CommonValidatorFunctions } from './CommonValidatorFunctions';
|
||||
import { KubernetesValidatorFunctions } from './KubernetesValidatorFunctions';
|
||||
import { Validators } from './types';
|
||||
|
||||
const defaultValidators: Validators = {
|
||||
isValidApiVersion: KubernetesValidatorFunctions.isValidApiVersion,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"incremental": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"lib": ["es2019"],
|
||||
"types": ["node", "jest"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user