Skip to content

Commit 0690472

Browse files
authored
Added support for headers (#1)
1 parent 9b02ae7 commit 0690472

File tree

15 files changed

+160
-26
lines changed

15 files changed

+160
-26
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"private": true,
44
"scripts": {
55
"dev": "pnpm --filter example run dev",
6-
"build": "pnpm --filter next-rest-framework run build",
6+
"build": "pnpm --filter next-rest-framework-patch-hugo run build",
77
"test": "pnpm --filter next-rest-framework run test",
88
"test:watch": "pnpm --filter next-rest-framework run test:watch",
99
"format": "prettier --write '**/*.{ts,json}' && eslint --fix --max-warnings=0 --ext=.ts .",

packages/next-rest-framework/package.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
{
2-
"name": "next-rest-framework-patch-hugo",
3-
"version": "6.0.8",
4-
"description": "A patch for Next REST Framework to work with Next.JS 15",
2+
"name": "next-rest-framework",
3+
"version": "6.0.7",
4+
"description": "Next REST Framework - Type-safe, self-documenting APIs for Next.js",
55
"keywords": [
66
"nextjs",
77
"rest",
88
"api",
99
"next-rest-framework"
1010
],
11-
"homepage": "https://github.com/Hugo-Persson/next-rest-framework-patch",
11+
"homepage": "https://next-rest-framework.vercel.app",
12+
"bugs": {
13+
"url": "https://github.com/blomqma/next-rest-framework/issues",
14+
"email": "[email protected]"
15+
},
1216
"license": "ISC",
13-
"author": "Hugo Persson",
17+
"author": "Markus Blomqvist <[email protected]>",
1418
"files": [
1519
"dist"
1620
],
@@ -19,7 +23,7 @@
1923
"types": "dist/index.d.ts",
2024
"repository": {
2125
"type": "git",
22-
"url": "https://github.com/Hugo-Persson/next-rest-framework-patch",
26+
"url": "https://github.com/blomqma/next-rest-framework.git",
2327
"directory": "packages/next-rest-framework"
2428
},
2529
"scripts": {

packages/next-rest-framework/src/app-router/route-operation.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
type BaseContentType,
1515
type ZodFormSchema,
1616
type FormDataContentType,
17-
type ContentTypesThatSupportInputValidation
17+
type ContentTypesThatSupportInputValidation,
18+
type BaseHeaders
1819
} from '../types';
1920
import { NextResponse, type NextRequest } from 'next/server';
2021
import { type ZodSchema, type z } from 'zod';
@@ -168,6 +169,7 @@ type TypedRouteHandler<
168169
Body = unknown,
169170
Query extends BaseQuery = BaseQuery,
170171
Params extends BaseParams = BaseParams,
172+
Headers extends BaseHeaders = BaseHeaders,
171173
Options extends BaseOptions = BaseOptions,
172174
ResponseBody = unknown,
173175
Status extends BaseStatus = BaseStatus,
@@ -185,15 +187,16 @@ type TypedRouteHandler<
185187
| void
186188
> = (
187189
req: TypedNextRequest<Method, ContentType, Body, Query>,
188-
context: { params: Params },
190+
context: { params: Params; headers: Headers },
189191
options: Options
190192
) => Promise<TypedResponse> | TypedResponse;
191193

192194
interface InputObject<
193195
ContentType = BaseContentType,
194196
Body = unknown,
195197
Query = BaseQuery,
196-
Params = BaseParams
198+
Params = BaseParams,
199+
Headers = BaseHeaders
197200
> {
198201
contentType?: ContentType;
199202
/*! Body schema is supported only for certain content types that support input validation. */
@@ -210,6 +213,7 @@ interface InputObject<
210213
params?: ZodSchema<Params>;
211214
/*! If defined, this will override the params schema for the OpenAPI spec. */
212215
paramsSchema?: OpenAPIV3_1.SchemaObject | OpenAPIV3_1.ReferenceObject;
216+
headers?: ZodSchema<Headers>;
213217
}
214218

215219
export interface RouteOperationDefinition<
@@ -246,7 +250,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
246250
middleware1?: RouteMiddleware<any, any>;
247251
middleware2?: RouteMiddleware<any, any>;
248252
middleware3?: RouteMiddleware<any, any>;
249-
handler?: TypedRouteHandler<any, any, any, any, any, any>;
253+
handler?: TypedRouteHandler<any, any, any, any, any, any, any>;
250254
}): RouteOperationDefinition<Method> => ({
251255
openApiOperation,
252256
method,
@@ -263,9 +267,10 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
263267
ContentType extends BaseContentType,
264268
Body,
265269
Query extends BaseQuery,
266-
Params extends BaseParams
270+
Params extends BaseParams,
271+
Headers extends BaseHeaders
267272
>(
268-
input: InputObject<ContentType, Body, Query, Params>
273+
input: InputObject<ContentType, Body, Query, Params, Headers>
269274
) => ({
270275
outputs: <
271276
ResponseBody,
@@ -314,6 +319,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
314319
Body,
315320
Query,
316321
Params,
322+
Headers,
317323
Options3,
318324
ResponseBody,
319325
Status,
@@ -337,6 +343,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
337343
Body,
338344
Query,
339345
Params,
346+
Headers,
340347
Options2,
341348
ResponseBody,
342349
Status,
@@ -359,6 +366,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
359366
Body,
360367
Query,
361368
Params,
369+
Headers,
362370
Options1,
363371
ResponseBody,
364372
Status,
@@ -374,6 +382,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
374382
Body,
375383
Query,
376384
Params,
385+
Headers,
377386
BaseOptions,
378387
ResponseBody,
379388
Status,
@@ -408,6 +417,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
408417
Body,
409418
Query,
410419
Params,
420+
Headers,
411421
Options3,
412422
ResponseBody,
413423
Status,
@@ -431,6 +441,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
431441
Body,
432442
Query,
433443
Params,
444+
Headers,
434445
Options2
435446
>
436447
) => createOperation({ input, middleware1, middleware2, handler })
@@ -452,6 +463,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
452463
Body,
453464
Query,
454465
Params,
466+
Headers,
455467
Options2,
456468
ResponseBody,
457469
Status,
@@ -473,6 +485,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
473485
ContentType,
474486
Body,
475487
Query,
488+
Headers,
476489
Params,
477490
Options2
478491
>
@@ -495,6 +508,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
495508
Body,
496509
Query,
497510
Params,
511+
Headers,
498512
Options1,
499513
ResponseBody,
500514
Status,
@@ -510,6 +524,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
510524
Body,
511525
Query,
512526
Params,
527+
Headers,
513528
Options1
514529
>
515530
) => createOperation({ input, middleware1, handler })
@@ -565,6 +580,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
565580
unknown,
566581
BaseQuery,
567582
BaseParams,
583+
BaseHeaders,
568584
Options3,
569585
ResponseBody,
570586
Status,
@@ -587,6 +603,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
587603
unknown,
588604
BaseQuery,
589605
BaseParams,
606+
BaseHeaders,
590607
Options2,
591608
ResponseBody,
592609
Status,
@@ -602,6 +619,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
602619
unknown,
603620
BaseQuery,
604621
BaseParams,
622+
BaseHeaders,
605623
Options1,
606624
ResponseBody,
607625
Status,
@@ -617,6 +635,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
617635
unknown,
618636
BaseQuery,
619637
BaseParams,
638+
BaseHeaders,
620639
BaseOptions,
621640
ResponseBody,
622641
Status,
@@ -641,6 +660,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
641660
unknown,
642661
BaseQuery,
643662
BaseParams,
663+
BaseHeaders,
644664
Options3
645665
>
646666
) =>
@@ -653,6 +673,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
653673
unknown,
654674
BaseQuery,
655675
BaseParams,
676+
BaseHeaders,
656677
Options2
657678
>
658679
) => createOperation({ middleware1, middleware2, handler })
@@ -664,6 +685,7 @@ export const routeOperation = <Method extends keyof typeof ValidMethod>({
664685
unknown,
665686
BaseQuery,
666687
BaseParams,
688+
BaseHeaders,
667689
Options1
668690
>
669691
) => createOperation({ middleware1, handler })

packages/next-rest-framework/src/app-router/route.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
type FormDataContentType,
99
type BaseOptions,
1010
type BaseParams,
11-
type OpenApiPathItem
11+
type OpenApiPathItem,
12+
type BaseHeaders
1213
} from '../types';
1314
import {
1415
type RouteOperationDefinition,
@@ -28,7 +29,7 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
2829
) => {
2930
const handler = async (
3031
_req: NextRequest,
31-
context: { params: Promise<BaseParams> }
32+
context: { params: Promise<BaseParams>; headers: BaseHeaders }
3233
) => {
3334
try {
3435
const operation = Object.entries(operations).find(
@@ -48,6 +49,7 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
4849
}
4950
);
5051
}
52+
context.headers = Object.fromEntries(_req.headers.entries());
5153

5254
const { input, handler, middleware1, middleware2, middleware3 } =
5355
operation;
@@ -65,7 +67,11 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
6567
let middlewareOptions: BaseOptions = {};
6668

6769
if (middleware1) {
68-
const res = await middleware1(reqClone, {...context, params: await context.params}, middlewareOptions);
70+
const res = await middleware1(
71+
reqClone,
72+
{ ...context, params: await context.params },
73+
middlewareOptions
74+
);
6975

7076
const isOptionsResponse = (res: unknown): res is BaseOptions =>
7177
typeof res === 'object';
@@ -77,7 +83,11 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
7783
}
7884

7985
if (middleware2) {
80-
const res2 = await middleware2(reqClone, {...context, params: await context.params}, middlewareOptions);
86+
const res2 = await middleware2(
87+
reqClone,
88+
{ ...context, params: await context.params },
89+
middlewareOptions
90+
);
8191

8292
if (res2 instanceof Response) {
8393
return res2;
@@ -88,7 +98,7 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
8898
if (middleware3) {
8999
const res3 = await middleware3(
90100
reqClone,
91-
{...context, params: await context.params},
101+
{ ...context, params: await context.params },
92102
middlewareOptions
93103
);
94104

@@ -106,7 +116,8 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
106116
body: bodySchema,
107117
query: querySchema,
108118
contentType: contentTypeSchema,
109-
params: paramsSchema
119+
params: paramsSchema,
120+
headers: headersSchema
110121
} = input;
111122

112123
const contentType = reqClone.headers.get('content-type')?.split(';')[0];
@@ -270,11 +281,32 @@ export const route = <T extends Record<string, RouteOperationDefinition>>(
270281

271282
context.params = data;
272283
}
284+
285+
if (headersSchema) {
286+
const { valid, errors, data } = validateSchema({
287+
schema: headersSchema,
288+
obj: context.headers
289+
});
290+
291+
if (!valid) {
292+
return NextResponse.json(
293+
{
294+
message: DEFAULT_ERRORS.invalidHeaders,
295+
errors
296+
},
297+
{
298+
status: 400
299+
}
300+
);
301+
}
302+
303+
context.headers = data;
304+
}
273305
}
274306

275307
const res = await handler?.(
276308
reqClone as TypedNextRequest,
277-
{...context, params: await context.params},
309+
{ ...context, params: await context.params },
278310
middlewareOptions
279311
);
280312

packages/next-rest-framework/src/cli/generate.ts

100644100755
File mode changed.

packages/next-rest-framework/src/cli/index.ts

100644100755
File mode changed.

packages/next-rest-framework/src/cli/utils.ts

100644100755
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,11 @@ export const generateOpenApiSpec = async ({
428428
};
429429

430430
const components = Object.keys(schemas).length
431-
? { components: { schemas: sortObjectByKeys(schemas) } }
431+
? {
432+
components: {
433+
schemas: sortObjectByKeys(schemas)
434+
}
435+
}
432436
: {};
433437

434438
const spec: OpenAPIV3_1.Document = merge(

packages/next-rest-framework/src/cli/validate.ts

100644100755
File mode changed.

packages/next-rest-framework/src/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export const DEFAULT_ERRORS = {
1010
operationNotAllowed: 'Operation not allowed.',
1111
invalidRequestBody: 'Invalid request body.',
1212
invalidQueryParameters: 'Invalid query parameters.',
13-
invalidPathParameters: 'Invalid path parameters.'
13+
invalidPathParameters: 'Invalid path parameters.',
14+
invalidHeaders: 'Invalid headers.'
1415
};
1516

1617
export enum ValidMethod {

0 commit comments

Comments
 (0)