Skip to content

Commit ad97629

Browse files
committed
Factor catalog server routes into separate files
1 parent 424dea3 commit ad97629

File tree

6 files changed

+195
-173
lines changed

6 files changed

+195
-173
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
`bootstrap-packages.json` has a list of packages known to contain somewhat-valid custom elements monifests. It's used to run an initial import of packages for the catalog.
1+
`bootstrap-packages.json` has a list of packages known to contain somewhat-valid custom elements manifests. It's used to run an initial import of packages for the catalog.

packages/catalog-server/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import {AddressInfo} from 'net';
8-
import {makeServer} from './lib/server.js';
8+
import {makeServer} from './lib/server/server.js';
99

1010
const PORT = process.env['PORT'] ? parseInt(process.env['PORT']) : 6451;
1111

packages/catalog-server/src/lib/server.ts

Lines changed: 0 additions & 171 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @license
3+
* Copyright 2022 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
import {readFile} from 'fs/promises';
7+
import {fileURLToPath} from 'url';
8+
import type {
9+
CustomElement,
10+
PackageInfo,
11+
PackageVersion,
12+
ValidationProblem,
13+
} from '@webcomponents/catalog-api/lib/schema.js';
14+
import type Koa from 'koa';
15+
import type {Catalog} from '../../catalog.js';
16+
17+
export const makeBootstrapPackagesRoute =
18+
(catalog: Catalog) => async (context: Koa.Context) => {
19+
const bootstrapListFilePath = fileURLToPath(
20+
new URL('../../../data/bootstrap-packages.json', import.meta.url)
21+
);
22+
const bootstrapListFile = await readFile(bootstrapListFilePath, 'utf-8');
23+
const bootstrapList = JSON.parse(bootstrapListFile);
24+
const packageNames = bootstrapList['packages'] as Array<string>;
25+
const results = await Promise.all(
26+
packageNames.map(
27+
async (
28+
packageName
29+
): Promise<
30+
| {error: unknown; packageName: string}
31+
| {
32+
packageName: string;
33+
elements: Array<CustomElement>;
34+
packageInfo?: PackageInfo | undefined;
35+
packageVersion?: PackageVersion | undefined;
36+
problems?: ValidationProblem[] | undefined;
37+
}
38+
> => {
39+
try {
40+
const importResult = await catalog.importPackage(packageName);
41+
const elements = await catalog.getCustomElements(
42+
packageName,
43+
'latest',
44+
undefined
45+
);
46+
return {
47+
packageName,
48+
elements,
49+
...importResult,
50+
};
51+
} catch (error) {
52+
return {
53+
packageName,
54+
error,
55+
};
56+
}
57+
}
58+
)
59+
);
60+
context.status = 200;
61+
context.type = 'html';
62+
context.body = `
63+
<h1>Bootstrap Import Results</h1>
64+
${results
65+
.map((result) => {
66+
const {packageName} = result;
67+
if ('error' in result) {
68+
return `
69+
<h3>${packageName}</h3>
70+
<code><pre>${result.error}</pre></code>
71+
`;
72+
} else {
73+
const {elements} = result;
74+
return `
75+
<h3>${packageName}</h3>
76+
<p>Imported ${elements.length} element${
77+
elements.length === 1 ? '' : 's'
78+
}</p>
79+
`;
80+
}
81+
})
82+
.join('\n')}
83+
`;
84+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
import {
8+
getGraphQLParameters,
9+
processRequest,
10+
renderGraphiQL,
11+
sendResult,
12+
shouldRenderGraphiQL,
13+
} from 'graphql-helix';
14+
import type {GraphQLSchema} from 'graphql';
15+
import type Koa from 'koa';
16+
17+
export const makeGraphQLRoute =
18+
(schema: GraphQLSchema) => async (context: Koa.Context) => {
19+
// Build the graphql-helix request object
20+
const request = {
21+
body: context.request.body,
22+
headers: context.req.headers,
23+
method: context.request.method,
24+
query: context.request.query,
25+
};
26+
27+
if (shouldRenderGraphiQL(request)) {
28+
// This renders the interactive GraphiQL interface.
29+
// We might want to turn this off in production, or limit its use to
30+
// project owners.
31+
context.body = renderGraphiQL({});
32+
} else {
33+
const params = getGraphQLParameters(request);
34+
const {operationName, query, variables} = params;
35+
36+
const result = await processRequest({
37+
operationName,
38+
query,
39+
variables,
40+
request,
41+
schema,
42+
});
43+
44+
if (result.type === 'RESPONSE') {
45+
// Log errors that are not normally logged.
46+
// The errors are actual Error objects, so we get the stack traces
47+
if (result.payload.errors && result.payload.errors.length > 0) {
48+
for (const e of result.payload.errors) {
49+
console.error(e);
50+
}
51+
}
52+
}
53+
54+
sendResult(result, context.response.res);
55+
}
56+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
import Koa from 'koa';
8+
import cors from '@koa/cors';
9+
import Router from '@koa/router';
10+
11+
import bodyParser from 'koa-bodyparser';
12+
13+
import {makeExecutableCatalogSchema} from '../graphql.js';
14+
import {Catalog} from '../catalog.js';
15+
import {FirestoreRepository} from '../firestore/firestore-repository.js';
16+
import {NpmAndUnpkgFiles} from '@webcomponents/custom-elements-manifest-tools/lib/npm-and-unpkg-files.js';
17+
18+
import {makeGraphQLRoute} from './routes/graphql.js';
19+
import {makeBootstrapPackagesRoute} from './routes/bootstrap-packages.js';
20+
21+
export const makeServer = async () => {
22+
const files = new NpmAndUnpkgFiles();
23+
const repository = new FirestoreRepository();
24+
const catalog = new Catalog({files, repository});
25+
const schema = await makeExecutableCatalogSchema(catalog);
26+
27+
const router = new Router();
28+
29+
router.use(bodyParser());
30+
31+
router.all('/graphql', makeGraphQLRoute(schema));
32+
33+
router.get('/bootstrap-packages', makeBootstrapPackagesRoute(catalog));
34+
35+
router.get('/', async (ctx) => {
36+
ctx.status = 200;
37+
ctx.type = 'html';
38+
ctx.body = `
39+
<h1>Web Components Registry</h1>
40+
<p>
41+
This server hosts a GraphQL API for interacting with the
42+
web components registry.
43+
</p>
44+
<p>See the interactive query editor at <a href="/graphql">/graphql</a>.
45+
`;
46+
});
47+
48+
const app = new Koa();
49+
app.use(cors());
50+
app.use(router.routes());
51+
app.use(router.allowedMethods());
52+
return app;
53+
};

0 commit comments

Comments
 (0)