Skip to content

Commit 234ae23

Browse files
oak to hono
1 parent d452ce0 commit 234ae23

File tree

17 files changed

+734
-249
lines changed

17 files changed

+734
-249
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# vscode
44
/.vscode
5+
dev.md
56

67
# dependencies
78
/node_modules

api/Users/getUserInfo.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
type Ctx,
3+
ValidationType,
4+
} from '@/endpoints.ts';
5+
import { z } from 'npm:zod';
6+
import { shouldBeUserId } from '@/lib/userIdCheck.ts';
7+
import { OptionalIUser } from '@/db/models/Users.ts';
8+
9+
/**
10+
* GET /api/getUserInfo
11+
*
12+
* What do: Log the user's log
13+
*/
14+
export async function GET(ctx: Ctx) {
15+
const requestData = ctx.get('dataValidation').user
16+
const query: QueryType = requestData.query;
17+
18+
// middleware converts userId to User
19+
const targetUser = query.userId;
20+
21+
const userData: OptionalIUser = {
22+
registerType: targetUser.registerType,
23+
registerDate: targetUser.registerDate,
24+
lastLoginDate: targetUser.lastLoginDate,
25+
email: targetUser.email,
26+
name: targetUser.name,
27+
username: targetUser.username,
28+
picture: targetUser.picture,
29+
...targetUser.socialMedias?.reduce(
30+
(
31+
acc: Record<string, string>,
32+
{ key, value }: { key: string; value: string }
33+
) => ({ ...acc, [key]: value }),
34+
{}
35+
),
36+
};
37+
38+
ctx.status(200);
39+
return await ctx.json(userData);
40+
}
41+
42+
// Configurations
43+
export const path = '/api/getUserInfo';
44+
export const validation: ValidationType = {
45+
query: {
46+
userId: shouldBeUserId,
47+
},
48+
};
49+
export const middlewares = ['auth:validToken'];
50+
51+
const querySchema = z.object(validation.query as z.ZodRawShape);
52+
type QueryType = z.infer<typeof querySchema>;

api/Users/whoAmI.ts

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,10 @@
11
import {
2-
type ctx,
3-
type MiddlewareDataArray,
4-
getDataFromMiddleware,
5-
SetResponse,
6-
ValidationType
2+
type Ctx,
73
} from '@/endpoints.ts';
84
import { IUser, OptionalIUser } from '@/db/models/Users.ts';
9-
import {z} from 'npm:zod';
105

11-
12-
13-
export const pattern = new URLPattern({ pathname: '/api/whoAmI' });
14-
export const validation: ValidationType = {
15-
// /api/whoAmI?test=anystring
16-
query: {
17-
test: z.string().min(4),
18-
},
19-
20-
// /api/whoAmI
21-
// {
22-
// test: 'anystring'
23-
// }
24-
body: z.object({
25-
test: z.string().optional(),
26-
}),
27-
}
28-
export const middlewares = [
29-
'auth:validToken',
30-
];
31-
32-
export function GET(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void {
33-
const data = getDataFromMiddleware(_middlewareDatas, 'auth:validToken');
6+
export function GET(ctx: Ctx) {
7+
const data = ctx.get('auth:validToken').user;
348
const user = data.user as IUser;
359

3610
const userData: OptionalIUser = {
@@ -41,14 +15,18 @@ export function GET(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void {
4115
name: user.name,
4216
username: user.username,
4317
picture: user.picture,
18+
...user.socialMedias?.reduce(
19+
(
20+
acc: Record<string, string>,
21+
{ key, value }: { key: string; value: string }
22+
) => ({ ...acc, [key]: value }),
23+
{}
24+
),
4425
};
4526

46-
user.socialMedias?.forEach((socialMedia) => {
47-
userData[socialMedia.key] = socialMedia.value;
48-
});
49-
50-
return SetResponse(ctx, {
51-
status: 200,
52-
body: userData,
53-
});
27+
ctx.status(200);
28+
return ctx.json(userData);
5429
}
30+
31+
export const path = '/api/whoAmI';
32+
export const middlewares = ['auth:validToken'];

api/noCommentTemplate.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
type ctx,
3+
type MiddlewareDataArray,
4+
getDataFromMiddleware,
5+
SetResponse,
6+
ValidationType,
7+
} from '@/endpoints.ts';
8+
import { z } from 'npm:zod';
9+
10+
/**
11+
* POST /api/log
12+
*
13+
* What do: Log the user's log
14+
*/
15+
export function POST(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void {
16+
const requestData = getDataFromMiddleware(
17+
_middlewareDatas,
18+
'dataValidation'
19+
).user;
20+
const body: BodyType = requestData.body;
21+
22+
console.log('new log', body.log);
23+
24+
return SetResponse(ctx, {
25+
status: 200,
26+
body: {},
27+
});
28+
}
29+
30+
// Configurations
31+
export const pattern = new URLPattern({ pathname: '/api/log' });
32+
export const validation: ValidationType = {
33+
query: {},
34+
body: z.object({
35+
log: z.string().min(1),
36+
}),
37+
};
38+
export const middlewares = ['auth:validToken'];
39+
40+
type BodyType = z.infer<typeof validation.body>;

api/template.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
type ctx,
3+
type MiddlewareDataArray,
4+
getDataFromMiddleware,
5+
SetResponse,
6+
ValidationType,
7+
} from '@/endpoints.ts';
8+
import { IUser } from '@/db/models/Users.ts';
9+
import { z } from 'npm:zod';
10+
11+
/**
12+
* STEP 1: (OPTIONAL) Do this setting on
13+
* If you using VSCode, enable 'editor.foldingImportsByDefault' to fold imports
14+
* and get better DX.
15+
*/
16+
17+
/**
18+
* STEP 2: (REQUIRED) Endpoint path implementation
19+
* Don't forget to add filepath to endpoints.ts's loadEndpoints function's return array.
20+
* Because Deno Deploy don't allow dynamic imports cause of security reasons.
21+
*/
22+
23+
/**
24+
* STEP 3: (REQUIRED) Readability
25+
* Don't want create a new file? Create it! Readability is most important thing.
26+
* Split to multiple files if you need. Single Responsibility Principle is base rule.
27+
*/
28+
29+
/**
30+
* POST /api/postEvent
31+
*
32+
* What do: Post the event
33+
*/
34+
export function POST(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void {
35+
// .user means user so developer level which not base(library) level
36+
const authData = getDataFromMiddleware(
37+
_middlewareDatas,
38+
'auth:validToken'
39+
).user;
40+
const user = authData as IUser;
41+
42+
const requestData = getDataFromMiddleware(
43+
_middlewareDatas,
44+
'dataValidation'
45+
).user;
46+
const query: QueryType = requestData.query;
47+
const body: BodyType = requestData.body;
48+
49+
console.log('logging', query.eventId);
50+
console.log('Another logging', body.name);
51+
52+
return SetResponse(ctx, {
53+
status: 200,
54+
body: {
55+
username: user.username,
56+
},
57+
});
58+
}
59+
60+
/**
61+
* GET /api/postEvent
62+
*
63+
* What do: Get the event
64+
*/
65+
export function GET(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void {
66+
return SetResponse(ctx, {
67+
status: 200,
68+
body: {},
69+
});
70+
// ...
71+
}
72+
73+
// Configurations
74+
export const pattern = new URLPattern({ pathname: '/api/postEvent' });
75+
export const validation: ValidationType = {
76+
// Please use for 'GET', 'DELETE', 'OPTIONS' or 'HEAD'
77+
// /api/postEvent?test=anystring
78+
query: {
79+
eventId: z.string().min(4),
80+
},
81+
82+
// Please use for 'POST', 'PUT' or 'PATCH'
83+
// /api/postEvent
84+
// {
85+
// name: 'anystring',
86+
// description: 'anystring',
87+
// }
88+
body: z.object({
89+
name: z.string().min(5),
90+
description: z.string().min(1),
91+
}),
92+
};
93+
export const middlewares = ['auth:validToken'];
94+
95+
const querySchema = z.object(validation.query as z.ZodRawShape);
96+
type QueryType = z.infer<typeof querySchema>;
97+
type BodyType = z.infer<typeof validation.body>;

db/models/Users.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import mongoose, { Document, Model } from 'npm:mongoose';
2+
import { Ctx } from '@/endpoints.ts';
3+
import { addBulletToLastTrace } from '@/lib/requestTracer.ts';
24

35
export interface IUser extends Document {
46
registerType: string;
@@ -96,9 +98,44 @@ const getUserIdByToken = async (token: string): Promise<string | null> => {
9698
* @param {string} uid - The user ID to check
9799
* @returns {Promise<IUser | null>} - The user object or null if not found
98100
*/
99-
const getUserById = async (uid: string): Promise<IUser | null> => {
101+
const getUserById = async (
102+
ctx: Ctx | null,
103+
uid: string
104+
): Promise<IUser | null> => {
105+
const startMS = Date.now();
100106
const user = await User.findOne({ uid });
107+
const duration = Date.now() - startMS;
108+
if (ctx) {
109+
addBulletToLastTrace(
110+
ctx,
111+
`db_query:findUserByUserID - duration: ${duration}ms`
112+
);
113+
}
101114
return user;
102115
};
103116

104-
export { User, isUserRegistered, getUserIdByToken, getUserById };
117+
const getUserByToken = async (
118+
ctx: Ctx | null,
119+
token: string
120+
): Promise<IUser | null> => {
121+
const startMS = Date.now();
122+
const user = await User.findOne({
123+
token,
124+
});
125+
const duration = Date.now() - startMS;
126+
if (ctx) {
127+
addBulletToLastTrace(
128+
ctx,
129+
`db_query:findUserByToken - duration: ${duration}ms`
130+
);
131+
}
132+
return user;
133+
};
134+
135+
export {
136+
User,
137+
isUserRegistered,
138+
getUserIdByToken,
139+
getUserById,
140+
getUserByToken,
141+
};

db/models/image.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import mongoose, { Document, Model } from 'npm:mongoose';
22

3+
34
interface IImage extends Document {
45
uid: string;
56
owner_uid: string;

db/mongodb.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import mongoose from 'npm:mongoose';
22
import { config } from 'https://deno.land/x/[email protected]/mod.ts';
3-
import { Middleware } from 'https://deno.land/x/[email protected]/middleware.ts';
4-
import process from "node:process";
5-
import { loop } from "@/lib/loop.ts";
3+
import process from 'node:process';
4+
import { loop } from '@/lib/loop.ts';
5+
import { Ctx } from '@/endpoints.ts';
6+
import { type StatusCode } from 'npm:hono/utils/http-status';
7+
import { endTrace, startTrace } from "@/lib/requestTracer.ts";
68

79
config({ export: true, path: '.env.local' });
810

@@ -26,11 +28,13 @@ async function connect() {
2628

2729
state = 'connecting';
2830
// console.log('Connecting to MongoDB...');
29-
startTime = Date.now();
31+
if (!startTime) {
32+
startTime = Date.now();
33+
}
3034
client;
3135

3236
try {
33-
client = await mongoose.connect((MONGODB_URL as string) || '')
37+
client = await mongoose.connect((MONGODB_URL as string) || '');
3438
} catch (err) {
3539
state = 'failed';
3640
stop();
@@ -59,7 +63,8 @@ async function connect() {
5963

6064
type DBState = 'not-started' | 'connecting' | 'failed' | 'connected';
6165

62-
const stateMiddleware: Middleware = (ctx, next) => {
66+
const dbStateMiddleware = async (ctx: Ctx, next: () => void) => {
67+
startTrace(ctx, 'Database state middleware');
6368
const DB_Responses: Record<DBState, { body: string; status: number }> = {
6469
'not-started': {
6570
body: 'Database connection not started',
@@ -84,12 +89,13 @@ const stateMiddleware: Middleware = (ctx, next) => {
8489
};
8590

8691
if (state !== 'connected') {
87-
ctx.response.status = DB_Responses[state as DBState].status;
88-
ctx.response.body = DB_Responses[state as DBState].body;
89-
return;
92+
ctx.status(DB_Responses[state as DBState].status as StatusCode);
93+
endTrace(ctx, 'Database state middleware');
94+
return await ctx.body(DB_Responses[state as DBState].body);;
9095
}
9196

92-
return next();
97+
endTrace(ctx, 'Database state middleware');
98+
return await next();
9399
};
94100

95-
export { client as default, connect, stateMiddleware };
101+
export { client as default, connect, dbStateMiddleware };

0 commit comments

Comments
 (0)