Skip to content

Commit 9aebf97

Browse files
committed
initial commit
0 parents  commit 9aebf97

File tree

18 files changed

+6287
-0
lines changed

18 files changed

+6287
-0
lines changed

.eslintrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"parser": "@typescript-eslint/parser",
3+
"parserOptions": {
4+
"project": ["./tsconfig.json"]
5+
},
6+
"extends": [
7+
"@omer-x/eslint-config",
8+
"@omer-x/eslint-config/typescript"
9+
],
10+
"rules": {
11+
}
12+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Omer Mecitoglu
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# Next OpenAPI Route Handler
2+
3+
[![npm version](https://badge.fury.io/js/%40omer-x%2Fopenapi-types.svg)](https://badge.fury.io/js/%40omer-x%2Fnext-openapi-route-handler)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
6+
## Overview
7+
8+
`Next OpenAPI Route Handler` is an open-source, lightweight, and easy-to-use Next.js plugin designed to build type-safe, self-documented APIs. It leverages TypeScript and Zod to create and validate route handlers, automatically generating OpenAPI documentation from your code. This package aims to simplify the process of building and documenting REST APIs with Next.js, ensuring your API endpoints are well-defined and compliant with OpenAPI specifications.
9+
10+
**Key Features:**
11+
- **Type-Safe API Endpoints**: Ensure your requests and responses are strongly typed with TypeScript.
12+
- **Schema Validation**: Use Zod schemas for object validation, automatically converted to JSON schema for OpenAPI.
13+
- **Auto-Generated Documentation**: Generate OpenAPI JSON specs from your route handlers.
14+
- **Integration with Next.js**: Works seamlessly with Next.js App Directory features.
15+
- **Customizable**: Compatible with existing Next.js projects and fully customizable to suit your needs.
16+
17+
> **Note:** This package has a peer dependency on [`Next OpenAPI.json Generator`](https://www.npmjs.com/package/@omer-x/next-openapi-json-generator) for extracting the generated OpenAPI JSON.
18+
19+
## Requirements
20+
21+
To use `@omer-x/next-openapi-route-handler`, you'll need the following dependencies in your Next.js project:
22+
23+
- [Next.js](https://nextjs.org/) >= v13
24+
- [TypeScript](https://www.typescriptlang.org/) >= v5
25+
- [Zod](https://zod.dev/) >= v3
26+
- [Next OpenAPI.json Generator](https://www.npmjs.com/package/@omer-x/next-openapi-json-generator)
27+
28+
## Installation
29+
30+
To install this package, along with its peer dependency, run:
31+
32+
```sh
33+
npm install @omer-x/next-openapi-route-handler @omer-x/next-openapi-json-generator
34+
```
35+
36+
## Usage
37+
38+
The `createRoute` function is used to define route handlers in a type-safe and self-documenting way. Below is a description of each property of the input parameter:
39+
40+
| Property | Type | Description |
41+
| ------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
42+
| operationId | `string` | Unique identifier for the operation. |
43+
| method | `HttpMethod` | HTTP method for the route (e.g., GET, POST, PUT, PATCH, DELETE). |
44+
| summary | `string` | Short summary of the operation. |
45+
| description | `string` | Detailed description of the operation. |
46+
| tags | `string[]` | Tags for categorizing the operation. |
47+
| pathParams | `ZodType` | Zod schema for validating path parameters. |
48+
| queryParams | `ZodType` | Zod schema for validating query parameters. |
49+
| requestBody | `ZodType` | Zod schema for the request body (required for POST/PUT/PATCH). |
50+
| action | `({ pathParams, queryParams, body }) => Promise<Response>` | Function handling the request, receiving pathParams, queryParams, and requestBody. |
51+
| responses | `Record<string, ResponseDefinition>` | Object defining possible responses, each with a description and optional content schema. |
52+
53+
## Example
54+
55+
Here's an example of how to use `createRoute` to define route handlers:
56+
57+
```typescript
58+
import createRoute from "@omer-x/next-openapi-route-handler";
59+
import z from "zod";
60+
61+
export const { GET } = createRoute({
62+
operationId: "getUser",
63+
method: "GET",
64+
summary: "Get a specific user by ID",
65+
description: "Retrieve detailed information about a user by their unique ID",
66+
tags: ["Users"],
67+
pathParams: z.object({
68+
id: z.string().describe("ID of the user"),
69+
}),
70+
action: ({ pathParams }) => {
71+
const userId = pathParams.id;
72+
// do something with userId
73+
return Response.json(userId);
74+
},
75+
responses: {
76+
200: {
77+
description: "Successful response",
78+
content: z.object({
79+
id: z.string().uuid(),
80+
name: z.string().min(1),
81+
email: z.string().email(),
82+
createdAt: z.date(),
83+
}),
84+
},
85+
404: { description: "User not found" },
86+
},
87+
});
88+
89+
export const { PATCH } = createRoute({
90+
operationId: "updateUser",
91+
method: "PATCH",
92+
summary: "Update a specific user by ID",
93+
description: "Update the details of an existing user identified by their unique ID",
94+
tags: ["Users"],
95+
pathParams: z.object({
96+
id: z.string().describe("ID of the user"),
97+
}),
98+
action: ({ pathParams }) => {
99+
const userId = pathParams.id;
100+
// do something with userId
101+
return Response.json(userId);
102+
},
103+
responses: {
104+
200: { description: "User updated successfully" },
105+
404: { description: "User not found" },
106+
409: { description: "Email already exists" },
107+
},
108+
});
109+
110+
export const { DELETE } = createRoute({
111+
operationId: "deleteUser",
112+
method: "DELETE",
113+
summary: "Delete a specific user by ID",
114+
description: "Remove a user from the system by their unique ID",
115+
tags: ["Users"],
116+
pathParams: z.object({
117+
id: z.string().describe("ID of the user"),
118+
}),
119+
action: ({ pathParams }) => {
120+
const userId = pathParams.id;
121+
// do something with userId
122+
return Response.json(userId);
123+
},
124+
responses: {
125+
204: { description: "User deleted successfully" },
126+
404: { description: "User not found" },
127+
},
128+
});
129+
```
130+
131+
This will generate an OpenAPI JSON like this:
132+
133+
```json
134+
{
135+
"openapi": "3.1.0",
136+
"info": {
137+
"title": "User Service",
138+
"version": "1.0.0"
139+
},
140+
"paths": {
141+
"/users/{id}": {
142+
"get": {
143+
"operationId": "getUser",
144+
"summary": "Get a specific user by ID",
145+
"description": "Retrieve detailed information about a user by their unique ID",
146+
"tags": ["Users"],
147+
"parameters": [
148+
{
149+
"in": "path",
150+
"name": "id",
151+
"required": true,
152+
"description": "ID of the user",
153+
"schema": {
154+
"type": "string"
155+
}
156+
}
157+
],
158+
"responses": {
159+
"200": {
160+
"description": "Successful response",
161+
"content": {
162+
"application/json": {
163+
"schema": {
164+
"type": "object",
165+
"properties": {
166+
"id": {
167+
"type": "string",
168+
"format": "uuid"
169+
},
170+
"name": {
171+
"type": "string",
172+
"minLength": 1
173+
},
174+
"email": {
175+
"type": "string",
176+
"format": "email"
177+
},
178+
"createdAt": {
179+
"type": "string",
180+
"format": "date-time"
181+
}
182+
},
183+
"required": ["id", "name", "email", "createdAt"],
184+
"additionalProperties": false
185+
}
186+
}
187+
}
188+
},
189+
"404": {
190+
"description": "User not found"
191+
}
192+
}
193+
},
194+
"patch": {
195+
"operationId": "updateUser",
196+
"summary": "Update a specific user by ID",
197+
"description": "Update the details of an existing user identified by their unique ID",
198+
"tags": ["Users"],
199+
"parameters": [
200+
{
201+
"in": "path",
202+
"name": "id",
203+
"required": true,
204+
"description": "ID of the user",
205+
"schema": {
206+
"type": "string"
207+
}
208+
}
209+
],
210+
"responses": {
211+
"200": {
212+
"description": "User updated successfully"
213+
},
214+
"404": {
215+
"description": "User not found"
216+
},
217+
"409": {
218+
"description": "Email already exists"
219+
}
220+
}
221+
},
222+
"delete": {
223+
"operationId": "deleteUser",
224+
"summary": "Delete a specific user by ID",
225+
"description": "Remove a user from the system by their unique ID",
226+
"tags": ["Users"],
227+
"parameters": [
228+
{
229+
"in": "path",
230+
"name": "id",
231+
"required": true,
232+
"description": "ID of the user",
233+
"schema": {
234+
"type": "string"
235+
}
236+
}
237+
],
238+
"responses": {
239+
"204": {
240+
"description": "User deleted successfully"
241+
},
242+
"404": {
243+
"description": "User not found"
244+
}
245+
}
246+
}
247+
}
248+
}
249+
}
250+
```
251+
252+
> **Important:** This package cannot extract the OpenAPI JSON by itself. Use [Next OpenAPI.json Generator](https://www.npmjs.com/package/@omer-x/next-openapi-json-generator) to extract the generated data as JSON.
253+
254+
## License
255+
256+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)