Skip to content

Commit ac8dfbb

Browse files
committed
inital typescript config and runtime
1 parent 880b742 commit ac8dfbb

File tree

4 files changed

+6041
-5437
lines changed

4 files changed

+6041
-5437
lines changed

lib/index.ts

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import Koa from 'koa';
2+
import Router from '@koa/router';
3+
import bodyParser from 'koa-bodyparser';
4+
import cors from '@koa/cors';
5+
import { v4 as uuidV4 } from 'uuid';
6+
import log from './utils/log.js';
7+
import apiRouter from './routes/index.js';
8+
9+
// Create the Koa instance
10+
const app = new Koa(),
11+
appRouter = new Router(),
12+
npmPackageVersion = process.env.npm_package_version || 'UNKNOWN';
13+
14+
// App setup
15+
app.proxy = true;
16+
app.proxyIpHeader = 'X-Real-IP';
17+
18+
/**
19+
* Attach API Version Header
20+
*/
21+
app.use(async (ctx, next) => {
22+
ctx.set('Api-Version', npmPackageVersion);
23+
24+
await next();
25+
});
26+
27+
/**
28+
* Attach a request id from downstream, or create one
29+
*/
30+
app.use(async (ctx, next) => {
31+
ctx.requestId = (typeof ctx.headers['request-id'] === 'string' && ctx.headers['request-id']) || uuidV4();
32+
33+
await next();
34+
});
35+
36+
// Attach routes to the app level router
37+
appRouter.use('/v1', apiRouter.routes());
38+
39+
/**
40+
* Attach CORS middleware
41+
*/
42+
// Cache this env value since it's checked on every request
43+
const corsEnv = process.env.NODE_ENV;
44+
app.use(
45+
cors({
46+
keepHeadersOnError: true,
47+
maxAge: 1728000,
48+
origin(ctx) {
49+
const origin = ctx.get('origin');
50+
51+
// Accept dev origins only in non-production environments
52+
if(corsEnv !== 'production' && /^https?:\/\/localhost(:\d*)?$/.test(origin)) {
53+
return origin;
54+
}
55+
56+
// Mustache bash root and single subdomain, HTTPS only
57+
if(/^https:\/\/(\w+\.)?mustachebash\.com$/.test(origin)) {
58+
return origin;
59+
}
60+
61+
return '';
62+
},
63+
credentials(ctx) {
64+
const origin = ctx.get('origin');
65+
66+
// Accept dev origins only in non-production environments
67+
if(corsEnv !== 'production' && /^https?:\/\/localhost(:\d*)?$/.test(origin)) {
68+
return true;
69+
}
70+
71+
// Mustache bash root and single subdomain, HTTPS only
72+
if(/^https:\/\/(\w+\.)?mustachebash\.com$/.test(origin)) {
73+
return true;
74+
}
75+
76+
return false;
77+
},
78+
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
79+
allowHeaders: [
80+
'Accept',
81+
'Authorization',
82+
'Cache-Control',
83+
'Content-Type',
84+
'DNT',
85+
'If-Modified-Since',
86+
'Keep-Alive',
87+
'Origin',
88+
'User-Agent',
89+
'X-Requested-With'
90+
],
91+
exposeHeaders: [
92+
'Location',
93+
'Retry-After',
94+
'Warning'
95+
]
96+
})
97+
);
98+
99+
/**
100+
* Attach the logger middleware
101+
* This will give middleware and route handlers access to ctx.log,
102+
* a child logger for each request
103+
*/
104+
app.use(async (ctx, next) => {
105+
ctx.log = log.child({requestId: ctx.requestId});
106+
107+
await next();
108+
109+
const { request, response } = ctx,
110+
message = `${request.method} ${request.originalUrl} ${response.status}`;
111+
112+
ctx.log.info({request, response, ctx}, message);
113+
});
114+
115+
/**
116+
* Attach response times
117+
*/
118+
app.use(async (ctx, next) => {
119+
// Hi-res time
120+
const start = process.hrtime();
121+
122+
try {
123+
await next();
124+
} finally {
125+
const [ seconds, nanoseconds ] = process.hrtime(start),
126+
{ response } = ctx;
127+
128+
response.responseTime = seconds * 1e3 + nanoseconds * 1e-6;
129+
}
130+
});
131+
132+
/**
133+
* Attach request body parser
134+
*/
135+
app.use(bodyParser());
136+
137+
/**
138+
* Attach the main router and all routes to the app
139+
*/
140+
app.use(appRouter.routes());
141+
142+
/**
143+
* Catch all other requests
144+
*/
145+
app.use(ctx => ctx.throw(404));
146+
147+
/**
148+
* Global error handler
149+
* Errors should be thrown directly from middleware and controllers to be handled here
150+
*/
151+
app.on('error', (err, ctx) => {
152+
const { request, response } = ctx;
153+
154+
response.status = err.status || response.status;
155+
156+
if(err.status < 500) {
157+
ctx.log.warn({request, response, ctx, err}, `${request.method} ${request.originalUrl} ${response.status} - ${err.message}`);
158+
} else {
159+
ctx.log.error({request, response, ctx, err}, err.message);
160+
}
161+
});
162+
163+
app.listen(4000, () => log.info(`Mustache Bash API ${process.env.npm_package_version} listening on port 4000`));

0 commit comments

Comments
 (0)