add stackoverflow api implementation
Signed-off-by: Brian Fletcher <brian@roadie.io>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 { createApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
StackOverflowQuestion,
|
||||
StackOverflowQuestionsRequestParams,
|
||||
} from '../types';
|
||||
|
||||
export const stackOverflowApiRef = createApiRef<StackOverflowApi>({
|
||||
id: 'plugin.stackoverflow.service',
|
||||
});
|
||||
|
||||
export type StackOverflowApi = {
|
||||
listQuestions(options?: {
|
||||
requestParams: StackOverflowQuestionsRequestParams;
|
||||
}): Promise<StackOverflowQuestion[]>;
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2021 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 { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { StackOverflowClient } from './index';
|
||||
import { StackOverflowQuestion } from '../types';
|
||||
|
||||
const server = setupServer();
|
||||
|
||||
const backstageQuestions: StackOverflowQuestion[] = [
|
||||
{
|
||||
title: 'What is it?',
|
||||
link: 'https://example.com:9191/questions/1',
|
||||
tags: ['asdf'],
|
||||
owner: { who: 'me' },
|
||||
answer_count: 3,
|
||||
},
|
||||
{
|
||||
title: 'Is it?',
|
||||
link: 'https://example.com:9191/questions/2',
|
||||
tags: ['asdf'],
|
||||
owner: { who: 'me' },
|
||||
answer_count: 4,
|
||||
},
|
||||
];
|
||||
|
||||
describe('StackOverflowClient', () => {
|
||||
setupRequestMockHandlers(server);
|
||||
|
||||
const mockBaseUrl = 'https://example.com:9191';
|
||||
|
||||
const setupHandlers = () => {
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/questions`, (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json({
|
||||
items:
|
||||
req.url.searchParams.get('tagged') === 'backstage'
|
||||
? backstageQuestions
|
||||
: [],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
it('list questions should return all questions', async () => {
|
||||
setupHandlers();
|
||||
const client = new StackOverflowClient({
|
||||
baseUrl: 'https://example.com:9191',
|
||||
});
|
||||
|
||||
const responseQuestions = await client.listQuestions({
|
||||
requestParams: { tagged: 'backstage' },
|
||||
});
|
||||
expect(responseQuestions.length).toEqual(2);
|
||||
expect(responseQuestions).toEqual(backstageQuestions);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2021 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 fetch from 'cross-fetch';
|
||||
import { StackOverflowApi } from './StackOverflowApi';
|
||||
import {
|
||||
StackOverflowQuestion,
|
||||
StackOverflowQuestionsRequestParams,
|
||||
} from '../types';
|
||||
import qs from 'qs';
|
||||
|
||||
export class StackOverflowClient implements StackOverflowApi {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor({ baseUrl }: { baseUrl: string }) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* List Questions in the StackOverflow instance
|
||||
*
|
||||
* */
|
||||
async listQuestions(options: {
|
||||
requestParams: StackOverflowQuestionsRequestParams;
|
||||
}): Promise<StackOverflowQuestion[]> {
|
||||
const params = qs.stringify(options.requestParams, {
|
||||
addQueryPrefix: true,
|
||||
});
|
||||
const response = await fetch(`${this.baseUrl}/questions${params}`);
|
||||
const data = await response.json();
|
||||
return data.items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An API definition and client for integrating with the StackOverflow Backend
|
||||
* API
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './StackOverflowApi';
|
||||
export * from './StackOverflowClient';
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useApi, configApiRef } from '@backstage/core-plugin-api';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import {
|
||||
IconButton,
|
||||
@@ -26,12 +26,12 @@ import {
|
||||
} from '@material-ui/core';
|
||||
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import qs from 'qs';
|
||||
import React from 'react';
|
||||
import {
|
||||
StackOverflowQuestion,
|
||||
StackOverflowQuestionsContentProps,
|
||||
} from '../../types';
|
||||
import { stackOverflowApiRef } from '../../api';
|
||||
|
||||
/**
|
||||
* A component to display a list of stack overflow questions on the homepage.
|
||||
@@ -41,18 +41,12 @@ import {
|
||||
|
||||
export const Content = (props: StackOverflowQuestionsContentProps) => {
|
||||
const { requestParams } = props;
|
||||
const configApi = useApi(configApiRef);
|
||||
const baseUrl =
|
||||
configApi.getOptionalString('stackoverflow.baseUrl') ||
|
||||
'https://api.stackexchange.com/2.2';
|
||||
const stackOverflowApi = useApi(stackOverflowApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<
|
||||
StackOverflowQuestion[]
|
||||
> => {
|
||||
const params = qs.stringify(requestParams, { addQueryPrefix: true });
|
||||
const response = await fetch(`${baseUrl}/questions${params}`);
|
||||
const data = await response.json();
|
||||
return data.items;
|
||||
return await stackOverflowApi.listQuestions({ requestParams });
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
import {
|
||||
createPlugin,
|
||||
createComponentExtension,
|
||||
createApiFactory,
|
||||
configApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { createCardExtension } from '@backstage/plugin-home';
|
||||
import { StackOverflowQuestionsContentProps } from './types';
|
||||
import { stackOverflowApiRef, StackOverflowClient } from './api';
|
||||
|
||||
/**
|
||||
* The Backstage plugin that holds stack overflow specific components
|
||||
@@ -28,6 +31,18 @@ import { StackOverflowQuestionsContentProps } from './types';
|
||||
*/
|
||||
export const stackOverflowPlugin = createPlugin({
|
||||
id: 'stack-overflow',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: stackOverflowApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) =>
|
||||
new StackOverflowClient({
|
||||
baseUrl:
|
||||
configApi.getOptionalString('stackoverflow.baseUrl') ||
|
||||
'https://api.stackexchange.com/2.2',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user