Merge pull request #1725 from spotify/blam/gql

Stand up a GraphQL Plugin
This commit is contained in:
Ben Lambert
2020-07-27 11:17:41 +02:00
committed by GitHub
16 changed files with 1185 additions and 83 deletions
+1
View File
@@ -30,6 +30,7 @@
"@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.16",
"@backstage/plugin-sentry-backend": "^0.1.1-alpha.16",
"@backstage/plugin-techdocs-backend": "^0.1.1-alpha.16",
"@backstage/plugin-graphql-backend": "^0.1.1-alpha.16",
"@octokit/rest": "^18.0.0",
"dockerode": "^3.2.0",
"express": "^4.17.1",
+4 -1
View File
@@ -38,6 +38,7 @@ import scaffolder from './plugins/scaffolder';
import sentry from './plugins/sentry';
import proxy from './plugins/proxy';
import techdocs from './plugins/techdocs';
import graphql from './plugins/graphql';
import { PluginEnvironment } from './types';
function makeCreateEnv(loadedConfigs: AppConfig[]) {
@@ -70,6 +71,7 @@ async function main() {
const rollbarEnv = useHotMemoize(module, () => createEnv('rollbar'));
const sentryEnv = useHotMemoize(module, () => createEnv('sentry'));
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
const graphqlEnv = useHotMemoize(module, () => createEnv('graphql'));
const service = createServiceBuilder(module)
.loadConfig(configReader)
@@ -80,7 +82,8 @@ async function main() {
.addRouter('/auth', await auth(authEnv))
.addRouter('/identity', await identity(identityEnv))
.addRouter('/techdocs', await techdocs(techdocsEnv))
.addRouter('/proxy', await proxy(proxyEnv));
.addRouter('/proxy', await proxy(proxyEnv))
.addRouter('/graphql', await graphql(graphqlEnv));
await service.start().catch(err => {
console.log(err);
+39
View File
@@ -0,0 +1,39 @@
/*
* 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.
*/
/*
* 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 { createRouter } from '@backstage/plugin-graphql-backend';
import type { PluginEnvironment } from '../types';
export default async function createPlugin({ logger }: PluginEnvironment) {
return await createRouter({
logger,
});
}
+1 -1
View File
@@ -50,7 +50,7 @@
"jest-fetch-mock": "^3.0.3",
"msw": "^0.19.0",
"react-test-renderer": "^16.13.1",
"whatwg-fetch": "^3.0.0"
"whatwg-fetch": "^2.0.0"
},
"files": [
"dist"
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
};
+14
View File
@@ -0,0 +1,14 @@
# graphql
Welcome to the graphql backend plugin!
_This plugin was created through the Backstage CLI_
## Getting started
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn
start` in the root directory, and then navigating to [/graphql](http://localhost:3000/graphql).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
+45
View File
@@ -0,0 +1,45 @@
{
"name": "@backstage/plugin-graphql-backend",
"version": "0.1.1-alpha.16",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"private": true,
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
},
"scripts": {
"start": "backstage-cli backend:dev",
"build": "backstage-cli backend:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"prepack": "backstage-cli prepack",
"postpack": "backstage-cli postpack",
"clean": "backstage-cli clean",
"mock-data": "./scripts/mock-data.sh"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.16",
"@types/express": "^4.17.6",
"apollo-server": "^2.16.0",
"apollo-server-express": "^2.16.0",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"graphql": "^15.3.0",
"whatwg-fetch": "^2.0.0",
"winston": "^3.2.1",
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.16",
"@types/supertest": "^2.0.8",
"eslint-plugin-graphql": "^4.0.0",
"msw": "^0.19.5",
"supertest": "^4.0.2"
},
"files": [
"dist"
]
}
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
echo "use this script to load your service with some mock data if needed!"
+19
View File
@@ -0,0 +1,19 @@
/*
* 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.
*/
require('whatwg-fetch');
export * from './service/router';
+33
View File
@@ -0,0 +1,33 @@
/*
* 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 { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
startStandaloneServer({ port, enableCors, logger }).catch(err => {
logger.error(err);
process.exit(1);
});
process.on('SIGINT', () => {
logger.info('CTRL+C pressed; exiting.');
process.exit(0);
});
+11
View File
@@ -0,0 +1,11 @@
type CatalogEntity {
id: String
}
type CatalogQuery {
list: [CatalogEntity!]!
}
type Query {
catalog: CatalogQuery!
}
@@ -0,0 +1,22 @@
/*
* 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 './router';
describe('Router', () => {
it('should pass the test', () => {
expect(true).toBeTruthy();
});
});
+50
View File
@@ -0,0 +1,50 @@
/*
* 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 { errorHandler } from '@backstage/backend-common';
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
import fs from 'fs';
import path from 'path';
import { ApolloServer } from 'apollo-server-express';
export interface RouterOptions {
logger: Logger;
}
export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const typeDefs = await fs.promises.readFile(
path.resolve(__dirname, '..', 'schema.gql'),
'utf-8',
);
const server = new ApolloServer({ typeDefs, logger: options.logger });
const router = Router();
const apolloMiddlware = server.getMiddleware({ path: '/' });
router.use(apolloMiddlware);
router.get('/health', (_, response) => {
response.send({ status: 'ok' });
});
router.use(errorHandler());
return router;
}
@@ -0,0 +1,62 @@
/*
* 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.
*/
/*
* 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 { createServiceBuilder } from '@backstage/backend-common';
import { Server } from 'http';
import { Logger } from 'winston';
import { createRouter } from './router';
export interface ServerOptions {
port: number;
enableCors: boolean;
logger: Logger;
}
export async function startStandaloneServer(
options: ServerOptions,
): Promise<Server> {
const logger = options.logger.child({ service: 'graphql-backend' });
logger.debug('Starting application server...');
const router = await createRouter({
logger,
});
const service = createServiceBuilder(module)
.enableCors({ origin: 'http://localhost:3000' })
.addRouter('/graphql', router);
return await service.start().catch(err => {
logger.error(err);
process.exit(1);
});
}
module.hot?.accept();
+18
View File
@@ -0,0 +1,18 @@
/*
* 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.
*/
require('whatwg-fetch');
export {};
+861 -81
View File
File diff suppressed because it is too large Load Diff