-
Notifications
You must be signed in to change notification settings - Fork 4
/
route.ts
117 lines (98 loc) · 2.91 KB
/
route.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { cookies } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import {
createAnimal,
getAnimalsWithLimitAndOffset,
} from '../../../database/animals';
import { getUserBySessionToken } from '../../../database/users';
import { Animal } from '../../../migrations/1675675178-createTableAnimals';
import { validateTokenAgainstSecret } from '../../../util/csrf';
const animalSchema = z.object({
firstName: z.string(),
type: z.string(),
accessory: z.string(),
csrfToken: z.string(),
});
export type AnimalsResponseBodyGet =
| {
error: string;
}
| {
animals: Animal[];
};
export type AnimalsResponseBodyPost =
| {
error: string;
}
| {
animal: Animal;
};
export async function GET(
request: NextRequest,
): Promise<NextResponse<AnimalsResponseBodyGet>> {
// this should be a public api method (unprotected)
const { searchParams } = new URL(request.url);
const limit = Number(searchParams.get('limit'));
const offset = Number(searchParams.get('offset'));
if (!limit || !offset) {
return NextResponse.json(
{
error: 'Limit and Offset need to be passed as params',
},
{ status: 400 },
);
}
const animals = await getAnimalsWithLimitAndOffset(limit, offset);
return NextResponse.json({ animals: animals });
}
export async function POST(
request: NextRequest,
): Promise<NextResponse<AnimalsResponseBodyPost>> {
// this is a protected Route Handler
// 1. get the session token from the cookie
const cookieStore = cookies();
const token = cookieStore.get('sessionToken');
// 2. validate that session
// 3. get the user profile matching the session
const user = token && (await getUserBySessionToken(token.value));
if (!user) {
return NextResponse.json({ error: 'session token is not valid' });
}
const body = await request.json();
const result = animalSchema.safeParse(body);
if (!result.success) {
// Inside of result.error.issues you are going to have more granular information about what is failing allowing you to create more specific error massages
// console.log(result.error.issues);
return NextResponse.json(
{
error:
'Request body is missing one of the needed properties firstName, type and accessory ',
},
{ status: 400 },
);
}
// validate csrf token to make sure the request happens from my server
if (!validateTokenAgainstSecret(user.csrfSecret, result.data.csrfToken)) {
return NextResponse.json(
{
error: 'CSRF token is not valid',
},
{ status: 400 },
);
}
const newAnimal = await createAnimal(
result.data.firstName,
result.data.type,
result.data.accessory,
);
if (!newAnimal) {
return NextResponse.json(
{
error: 'Animal not created!',
},
{ status: 500 },
);
}
return NextResponse.json({ animal: newAnimal });
}