Add a discovery API
Signed-off-by: Karan Shah <karan.shah@simplybusiness.co.uk>
This commit is contained in:
@@ -71,12 +71,6 @@ export const ApiBar = () => {
|
||||
value.setProjectId?.(parseInt(e.target.value, 10) || undefined)
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
label="API Key"
|
||||
variant="outlined"
|
||||
defaultValue={value.apiKey}
|
||||
onChange={e => value.setApiKey?.(e.target.value)}
|
||||
/>
|
||||
</MuiThemeProvider>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -23,23 +23,18 @@ import React, {
|
||||
interface ContextInterface {
|
||||
projectId?: number;
|
||||
setProjectId?: Dispatch<SetStateAction<number | undefined>>;
|
||||
apiKey?: string;
|
||||
setApiKey?: Dispatch<SetStateAction<string>>;
|
||||
}
|
||||
|
||||
export const Context = React.createContext<ContextInterface>({});
|
||||
|
||||
export const ContextProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const [projectId, setProjectId] = useState<number>();
|
||||
const [apiKey, setApiKey] = useState<string>('');
|
||||
|
||||
return (
|
||||
<Context.Provider
|
||||
value={{
|
||||
projectId,
|
||||
setProjectId,
|
||||
apiKey,
|
||||
setApiKey,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -19,13 +19,14 @@ import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { airbrakePlugin, EntityAirbrakeContent } from '../src';
|
||||
import {
|
||||
airbrakeApiRef,
|
||||
localDiscoveryApi,
|
||||
MockAirbrakeApi,
|
||||
ProductionAirbrakeApi,
|
||||
} from '../src/api';
|
||||
import { ApiBar } from './components/ApiBar';
|
||||
import { Content, Header, Page } from '@backstage/core-components';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
import { createEntity } from '../src/api/mock/MockEntity';
|
||||
import { createEntity } from '../src/api';
|
||||
import CloudOffIcon from '@material-ui/icons/CloudOff';
|
||||
import CloudIcon from '@material-ui/icons/Cloud';
|
||||
import { Context, ContextProvider } from './components/ContextProvider';
|
||||
@@ -61,7 +62,10 @@ createDevApp()
|
||||
{value => (
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[airbrakeApiRef, new ProductionAirbrakeApi(value.apiKey)],
|
||||
[
|
||||
airbrakeApiRef,
|
||||
new ProductionAirbrakeApi(localDiscoveryApi),
|
||||
],
|
||||
]}
|
||||
>
|
||||
<EntityProvider entity={createEntity(value.projectId)}>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.9.10",
|
||||
"@backstage/core-components": "^0.8.8",
|
||||
"@backstage/core-app-api": "^0.5.2",
|
||||
"@backstage/core-plugin-api": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.2.21",
|
||||
"@backstage/plugin-catalog-react": "^0.6.14",
|
||||
@@ -39,7 +40,6 @@
|
||||
"devDependencies": {
|
||||
"@backstage/app-defaults": "^0.1.7",
|
||||
"@backstage/cli": "^0.13.2",
|
||||
"@backstage/core-app-api": "^0.5.2",
|
||||
"@backstage/dev-utils": "^0.2.21",
|
||||
"@backstage/test-utils": "^0.2.4",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
|
||||
@@ -19,21 +19,19 @@ import { rest } from 'msw';
|
||||
import mockGroupsData from './mock/airbrakeGroupsApiMock.json';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import { localDiscoveryApi } from './mock';
|
||||
|
||||
describe('The production Airbrake API', () => {
|
||||
const productionApi = new ProductionAirbrakeApi('fakeApiKey');
|
||||
const productionApi = new ProductionAirbrakeApi(localDiscoveryApi);
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
it('fetches groups using the provided project ID', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://api.airbrake.io/api/v4/projects/123456/groups',
|
||||
(req, res, ctx) => {
|
||||
if (req.url.searchParams.get('key') === 'fakeApiKey') {
|
||||
return res(ctx.status(200), ctx.json(mockGroupsData));
|
||||
}
|
||||
return res(ctx.status(401));
|
||||
'http://localhost:7007/api/airbrake/api/v4/projects/123456/groups',
|
||||
(_, res, ctx) => {
|
||||
return res(ctx.status(200), ctx.json(mockGroupsData));
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -46,7 +44,7 @@ describe('The production Airbrake API', () => {
|
||||
it('throws if fetching groups was unsuccessful', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://api.airbrake.io/api/v4/projects/123456/groups',
|
||||
'http://localhost:7007/api/airbrake/api/v4/projects/123456/groups',
|
||||
(_, res, ctx) => {
|
||||
return res(ctx.status(500));
|
||||
},
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
import { Groups } from './airbrakeGroups';
|
||||
import { AirbrakeApi } from './AirbrakeApi';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export class ProductionAirbrakeApi implements AirbrakeApi {
|
||||
constructor(private readonly apiKey?: string) {}
|
||||
constructor(private readonly discoveryApi: DiscoveryApi) {}
|
||||
|
||||
async fetchGroups(projectId: string): Promise<Groups> {
|
||||
const apiUrl = `https://api.airbrake.io/api/v4/projects/${projectId}/groups?key=${this.apiKey}`;
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('airbrake');
|
||||
const apiUrl = `${baseUrl}/api/v4/projects/${projectId}/groups`;
|
||||
|
||||
const response = await fetch(apiUrl);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 { UrlPatternDiscovery } from '@backstage/core-app-api';
|
||||
|
||||
export const localDiscoveryApi = UrlPatternDiscovery.compile(
|
||||
'http://localhost:7007/api/{{ pluginId }}',
|
||||
);
|
||||
@@ -14,4 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { MockAirbrakeApi } from './MockApi';
|
||||
export * from './MockApi';
|
||||
export * from './MockEntity';
|
||||
export * from './LocalDiscoveryApi';
|
||||
|
||||
@@ -23,9 +23,10 @@ import {
|
||||
setupRequestMockHandlers,
|
||||
TestApiProvider,
|
||||
} from '@backstage/test-utils';
|
||||
import { createEntity } from '../../api/mock/MockEntity';
|
||||
import { createEntity } from '../../api';
|
||||
import {
|
||||
airbrakeApiRef,
|
||||
localDiscoveryApi,
|
||||
MockAirbrakeApi,
|
||||
ProductionAirbrakeApi,
|
||||
} from '../../api';
|
||||
@@ -65,7 +66,7 @@ describe('EntityAirbrakeContent', () => {
|
||||
it('states that an error occurred if the API call fails', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://api.airbrake.io/api/v4/projects/123/groups',
|
||||
'http://localhost:7007/api/airbrake/api/v4/projects/123/groups',
|
||||
(_, res, ctx) => {
|
||||
return res(ctx.status(500));
|
||||
},
|
||||
@@ -76,7 +77,7 @@ describe('EntityAirbrakeContent', () => {
|
||||
const widget = await renderInTestApp(
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[airbrakeApiRef, new ProductionAirbrakeApi('fakeApiKey')],
|
||||
[airbrakeApiRef, new ProductionAirbrakeApi(localDiscoveryApi)],
|
||||
[errorApiRef, mockErrorApi],
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -18,7 +18,7 @@ import { EntityAirbrakeContent } from './extensions';
|
||||
import { Route } from 'react-router';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { airbrakeApiRef, MockAirbrakeApi } from './api';
|
||||
import { createEntity } from './api/mock/MockEntity';
|
||||
import { createEntity } from './api';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
|
||||
describe('The Airbrake entity', () => {
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createApiFactory, createPlugin } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
import { airbrakeApiRef, ProductionAirbrakeApi } from './api';
|
||||
@@ -23,8 +27,8 @@ export const airbrakePlugin = createPlugin({
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: airbrakeApiRef,
|
||||
deps: {},
|
||||
factory: () => new ProductionAirbrakeApi(),
|
||||
deps: { discoveryApi: discoveryApiRef },
|
||||
factory: ({ discoveryApi }) => new ProductionAirbrakeApi(discoveryApi),
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
|
||||
Reference in New Issue
Block a user