Skip to content

Commit f41240b

Browse files
committed
[migrate] replace Next.js API handler with Koa router
1 parent 317558d commit f41240b

File tree

8 files changed

+94
-82
lines changed

8 files changed

+94
-82
lines changed

models/Base.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { HTTPClient } from 'koajax';
2+
import { githubClient } from 'mobx-github';
23

34
export const isServer = () => typeof window === 'undefined';
45

@@ -15,6 +16,22 @@ export const ownClient = new HTTPClient({
1516
responseType: 'json',
1617
});
1718

19+
const GithubToken = process.env.GITHUB_TOKEN;
20+
21+
if (!isServer()) githubClient.baseURI = `${API_Host}/api/GitHub/`;
22+
23+
githubClient.use(({ request }, next) => {
24+
if (GithubToken)
25+
request.headers = {
26+
authorization: `Bearer ${GithubToken}`,
27+
...request.headers,
28+
};
29+
30+
return next();
31+
});
32+
33+
export { githubClient };
34+
1835
export interface Base {
1936
id: number;
2037
createdAt: string;

models/Repository.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
11
import {
2-
githubClient,
32
GitRepository,
43
RepositoryFilter,
54
RepositoryModel as GitRepoModel,
65
} from 'mobx-github';
76
import { Stream } from 'mobx-restful';
87

9-
import { API_Host, isServer } from './Base';
10-
11-
const GithubToken = process.env.GITHUB_TOKEN;
12-
13-
if (!isServer()) githubClient.baseURI = `${API_Host}/api/GitHub/`;
14-
15-
githubClient.use(({ request }, next) => {
16-
if (GithubToken)
17-
request.headers = {
18-
authorization: `Bearer ${GithubToken}`,
19-
...request.headers,
20-
};
21-
return next();
22-
});
23-
248
const MainOrganization = 'freeCodeCamp-China';
259

2610
export class RepositoryModel extends Stream<GitRepository, RepositoryFilter>(
@@ -50,7 +34,7 @@ export class RepositoryModel extends Stream<GitRepository, RepositoryFilter>(
5034
}
5135

5236
if (hasAdditional)
53-
// @ts-ignore
37+
// @ts-expect-error Mixin type issue
5438
yield await this.getOne('freeCodeCamp/chinese', filter.relation);
5539
}
5640
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@fortawesome/react-fontawesome": "^0.2.6",
1414
"@giscus/react": "^3.1.0",
1515
"idea-react": "^2.0.0-rc.13",
16+
"koa": "^3.1.1",
1617
"koajax": "^3.1.2",
1718
"less": "^4.4.2",
1819
"less-loader": "^12.3.0",
@@ -46,6 +47,7 @@
4647
"@softonus/prettier-plugin-duplicate-remover": "^1.1.2",
4748
"@stylistic/eslint-plugin": "^5.5.0",
4849
"@types/eslint-config-prettier": "^6.11.3",
50+
"@types/koa": "^3.0.1",
4951
"@types/lodash": "^4.17.20",
5052
"@types/next-pwa": "^5.6.9",
5153
"@types/node": "^22.19.0",

pages/api/GitHub/[...slug].ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1-
import { proxyGithub } from './core';
1+
import { createKoaRouter, withKoaRouter } from 'next-ssr-middleware';
22

3-
export default proxyGithub();
3+
import { safeAPI } from '../core';
4+
import { proxyGitHubAll } from './core';
5+
6+
export const config = { api: { bodyParser: false } };
7+
8+
const router = createKoaRouter(import.meta.url);
9+
10+
router.get('/(.*)', safeAPI, proxyGitHubAll);
11+
12+
export default withKoaRouter(router);

pages/api/GitHub/core.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
1-
import { githubClient } from 'mobx-github';
1+
import { Context, Middleware } from 'koa';
2+
import { githubOAuth2 } from 'next-ssr-middleware';
23

3-
import { safeAPI } from '../core';
4+
import { githubClient } from '../../../models/Base';
45

5-
export const proxyGithub = <T>(dataFilter?: (path: string, data: T) => T) =>
6-
safeAPI(async ({ method, url, headers, body }, response) => {
7-
delete headers.host;
6+
export const proxyGithub = async <T>({
7+
method,
8+
url,
9+
headers: { host, ...headers },
10+
request,
11+
}: Context) => {
12+
const path = url!.slice(`/api/GitHub/`.length),
13+
body = Reflect.get(request, 'body');
814

9-
const path = url!.slice(`/api/GitHub/`.length);
15+
// @ts-expect-error KoAJAX type compatibility
16+
return githubClient.request<T>({ method, path, headers, body });
17+
};
1018

11-
const { status, body: data } = await githubClient.request<T>({
12-
// @ts-expect-error Upstream Type compatibility issue
13-
method,
14-
path,
15-
// @ts-expect-error Upstream Type compatibility issue
16-
headers,
17-
body: body || undefined,
18-
});
19+
export const proxyGitHubAll: Middleware = async context => {
20+
const { status, body } = await proxyGithub(context);
1921

20-
response.status(status);
21-
response.send(dataFilter?.(path, data as T) || data);
22-
});
22+
context.status = status;
23+
context.body = body;
24+
};
25+
26+
const client_id = process.env.GITHUB_OAUTH_CLIENT_ID!,
27+
client_secret = process.env.GITHUB_OAUTH_CLIENT_SECRET!;
28+
29+
export const ProxyBaseURL = 'https://chinese.fcc-cd.dev/proxy';
30+
31+
export const githubSigner = githubOAuth2({
32+
rootBaseURL: process.env.VERCEL ? undefined : `${ProxyBaseURL}/github.com/`,
33+
client_id,
34+
client_secret,
35+
scopes: ['user:email', 'read:user', 'public_repo', 'read:project'],
36+
});

pages/api/core.ts

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,38 @@
1+
import { Context, Middleware } from 'koa';
12
import { HTTPError } from 'koajax';
2-
import { NextApiRequest, NextApiResponse } from 'next';
3-
import { githubOAuth2 } from 'next-ssr-middleware';
43
import { ProxyAgent, setGlobalDispatcher } from 'undici';
54

65
const { HTTP_PROXY } = process.env;
76

87
if (HTTP_PROXY) setGlobalDispatcher(new ProxyAgent(HTTP_PROXY));
98

10-
export type NextAPI = (
11-
req: NextApiRequest,
12-
res: NextApiResponse,
13-
) => Promise<any>;
9+
export const safeAPI: Middleware<any, any> = async (context: Context, next) => {
10+
try {
11+
return await next();
12+
} catch (error) {
13+
if (!(error instanceof HTTPError)) {
14+
console.error(error);
1415

15-
export function safeAPI(handler: NextAPI): NextAPI {
16-
return async (req, res) => {
17-
try {
18-
return await handler(req, res);
19-
} catch (error) {
20-
if (!(error instanceof HTTPError)) {
21-
console.error(error);
16+
context.status = 400;
2217

23-
res.status(400);
24-
25-
return res.send({ message: (error as Error).message });
26-
}
27-
const { message, response } = error;
28-
let { body } = response;
29-
30-
res.status(response.status);
31-
res.statusMessage = message;
32-
33-
if (body instanceof ArrayBuffer)
34-
try {
35-
body = new TextDecoder().decode(new Uint8Array(body));
36-
console.error(body);
37-
38-
body = JSON.parse(body);
39-
console.error(body);
40-
} catch {
41-
//
42-
}
43-
res.send(body);
18+
return (context.body = { message: (error as Error).message });
4419
}
45-
};
46-
}
20+
const { message, response } = error;
21+
let { body } = response;
4722

48-
const client_id = process.env.GITHUB_OAUTH_CLIENT_ID!,
49-
client_secret = process.env.GITHUB_OAUTH_CLIENT_SECRET!;
23+
context.status = response.status;
24+
context.statusMessage = message;
5025

51-
export const ProxyBaseURL = 'https://chinese.fcc-cd.dev/proxy';
26+
if (body instanceof ArrayBuffer)
27+
try {
28+
body = new TextDecoder().decode(new Uint8Array(body));
29+
30+
body = JSON.parse(body);
31+
} catch {
32+
//
33+
}
34+
console.error(JSON.stringify(body, null, 2));
5235

53-
export const githubSigner = githubOAuth2({
54-
rootBaseURL: process.env.VERCEL ? undefined : `${ProxyBaseURL}/github.com/`,
55-
client_id,
56-
client_secret,
57-
scopes: ['user:email', 'read:user', 'public_repo', 'read:project'],
58-
});
36+
context.body = body;
37+
}
38+
};

pages/user/session.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Container } from 'react-bootstrap';
77
import { PageHead } from '../../components/PageHead';
88
import { i18n, I18nContext } from '../../models/Translation';
99
import { UserModel } from '../../models/User';
10-
import { githubSigner } from '../api/core';
10+
import { githubSigner } from '../api/GitHub/core';
1111

1212
export const getServerSideProps = compose(githubSigner);
1313

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)