Skip to content

Commit a5eeb7b

Browse files
author
Lasim
committed
feat: Enhance users API with detailed response schemas and OpenAPI documentation
- Added response schemas for user operations including success and error responses. - Updated existing routes to include OpenAPI schema definitions for better documentation. - Implemented user statistics retrieval and role-based user listing with appropriate schemas. - Improved error handling and response consistency across user-related endpoints.
1 parent 79a5d70 commit a5eeb7b

24 files changed

+5768
-609
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ services/backend/tests/e2e/test-data/*.db
6767
._*.json
6868
cookies.txt
6969
cookiejar.txt
70+
services/backend/tests/e2e/.test-context.json

package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/backend/API_DOCUMENTATION.md

Lines changed: 131 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This document explains how to generate and use the OpenAPI specification for the
44

55
## Overview
66

7-
The DeployStack Backend uses Fastify with Swagger plugins to automatically generate OpenAPI 3.0 specifications from route definitions. This provides:
7+
The DeployStack Backend uses Fastify with Swagger plugins to automatically generate OpenAPI 3.0 specifications. Route schemas are defined using [Zod](https://zod.dev/) for type safety and expressiveness, and then converted to JSON Schema using the [zod-to-json-schema](https://www.npmjs.com/package/zod-to-json-schema) library. This provides:
88

99
- **Interactive Documentation**: Swagger UI interface for testing APIs
1010
- **Postman Integration**: JSON/YAML specs that can be imported into Postman
@@ -86,31 +86,145 @@ When the server is running (`npm run dev`), you can access:
8686

8787
## Adding Documentation to Routes
8888

89-
To add OpenAPI documentation to your routes, include a schema object:
89+
To add OpenAPI documentation to your routes, define your request body and response schemas using Zod. Then, use the `zodToJsonSchema` utility to convert these Zod schemas into the JSON Schema format expected by Fastify.
90+
91+
Make sure you have `zod` and `zod-to-json-schema` installed in your backend service.
92+
93+
### Recommended Approach: Automatic Validation with Zod
94+
95+
The power of Zod lies in providing **automatic validation** through Fastify's schema system. This approach eliminates manual validation and leverages Zod's full validation capabilities.
9096

9197
```typescript
98+
import { z } from 'zod';
99+
import { zodToJsonSchema } from 'zod-to-json-schema';
100+
101+
// 1. Define your Zod schemas for request body, responses, etc.
102+
const myRequestBodySchema = z.object({
103+
name: z.string().min(3).describe("The name of the item (min 3 chars)"),
104+
count: z.number().positive().describe("How many items (must be positive)"),
105+
type: z.enum(['mysql', 'sqlite']).describe("Database engine type")
106+
});
107+
108+
const mySuccessResponseSchema = z.object({
109+
success: z.boolean().describe("Indicates if the operation was successful"),
110+
itemId: z.string().uuid().describe("The UUID of the created/affected item"),
111+
message: z.string().optional().describe("Optional success message")
112+
});
113+
114+
const myErrorResponseSchema = z.object({
115+
success: z.boolean().default(false).describe("Indicates failure"),
116+
error: z.string().describe("Error message detailing what went wrong")
117+
});
118+
119+
// 2. Construct the Fastify route schema using zodToJsonSchema
92120
const routeSchema = {
93-
tags: ['Category'],
94-
summary: 'Brief description',
95-
description: 'Detailed description of what this endpoint does',
96-
security: [{ cookieAuth: [] }], // If authentication required
121+
tags: ['Category'], // Your API category
122+
summary: 'Brief description of your endpoint',
123+
description: 'Detailed description of what this endpoint does, its parameters, and expected outcomes.',
124+
security: [{ cookieAuth: [] }], // Include if authentication is required
125+
body: zodToJsonSchema(myRequestBodySchema, {
126+
$refStrategy: 'none', // Keeps definitions inline, often simpler for Fastify
127+
target: 'openApi3' // Ensures compatibility with OpenAPI 3.0
128+
}),
97129
response: {
98-
200: {
99-
type: 'object',
100-
properties: {
101-
success: { type: 'boolean' },
102-
message: { type: 'string' }
103-
},
104-
required: ['success', 'message']
105-
}
130+
200: zodToJsonSchema(mySuccessResponseSchema.describe("Successful operation"), {
131+
$refStrategy: 'none',
132+
target: 'openApi3'
133+
}),
134+
400: zodToJsonSchema(myErrorResponseSchema.describe("Bad Request - Invalid input"), {
135+
$refStrategy: 'none',
136+
target: 'openApi3'
137+
}),
138+
// Define other responses (e.g., 401, 403, 404, 500) similarly
106139
}
107140
};
108141

109-
fastify.post('/your-route', { schema: routeSchema }, async (request, reply) => {
110-
// Your route handler
111-
});
142+
// 3. Use the schema in your Fastify route definition with proper TypeScript typing
143+
interface RequestBody {
144+
name: string;
145+
count: number;
146+
type: 'mysql' | 'sqlite';
147+
}
148+
149+
fastify.post<{ Body: RequestBody }>(
150+
'/your-route',
151+
{ schema: routeSchema },
152+
async (request, reply) => {
153+
// ✅ Fastify has already validated request.body using our Zod schema
154+
// ✅ If we reach here, request.body is guaranteed to be valid
155+
// ✅ No manual validation needed!
156+
157+
const { name, count, type } = request.body; // Fully typed and validated
158+
159+
// Your route handler logic here
160+
return reply.status(200).send({
161+
success: true,
162+
itemId: 'some-uuid-v4-here',
163+
message: `Item ${name} processed successfully with ${count} items using ${type}.`
164+
});
165+
}
166+
);
112167
```
113168

169+
### Key Benefits of This Approach
170+
171+
1. **Single Source of Truth**: Zod schemas define both validation AND documentation
172+
2. **Automatic Validation**: Fastify automatically validates requests before your handler runs
173+
3. **No Manual Validation**: Remove all manual `zod.parse()` calls and field checks
174+
4. **Better Error Messages**: Fastify provides detailed validation errors automatically
175+
5. **Type Safety**: Handlers receive properly typed, validated data
176+
6. **Cleaner Code**: No redundant validation logic in handlers
177+
178+
### What NOT to Do (Anti-patterns)
179+
180+
**Don't do manual validation in handlers:**
181+
```typescript
182+
// BAD: Manual validation (redundant)
183+
const parsedBody = myRequestBodySchema.safeParse(request.body);
184+
if (!parsedBody.success) {
185+
return reply.status(400).send({ error: 'Invalid request body' });
186+
}
187+
188+
// BAD: Manual field checks (redundant)
189+
if (!request.body.name || !request.body.count) {
190+
return reply.status(400).send({ error: 'Required fields missing' });
191+
}
192+
193+
// BAD: Manual enum validation (redundant)
194+
if (request.body.type !== 'mysql' && request.body.type !== 'sqlite') {
195+
return reply.status(400).send({ error: 'Invalid database type' });
196+
}
197+
```
198+
199+
**Do trust Fastify's automatic validation:**
200+
```typescript
201+
// GOOD: Trust the validation - if handler runs, data is valid
202+
const { name, count, type } = request.body; // Already validated by Fastify
203+
```
204+
205+
### Validation Flow
206+
207+
The validation chain works as follows:
208+
209+
**Zod Schema → JSON Schema → Fastify Validation → Handler**
210+
211+
1. **Zod Schema**: Define validation rules using Zod
212+
2. **JSON Schema**: Convert to OpenAPI format using `zodToJsonSchema()`
213+
3. **Fastify Validation**: Fastify automatically validates incoming requests
214+
4. **Handler**: Receives validated, typed data
215+
216+
If validation fails, Fastify automatically returns a 400 error **before** your handler runs.
217+
218+
### Real-World Examples
219+
220+
See these files for complete examples of proper Zod validation:
221+
- `src/routes/db/setup.ts` - Database setup with enum validation
222+
- `src/routes/db/status.ts` - Simple GET endpoint with response schemas
223+
- `src/routes/auth/loginEmail.ts` - Login with required string fields
224+
- `src/routes/auth/registerEmail.ts` - Registration with complex validation rules
225+
226+
**Note**: Older examples in this document (like the "Logout Route Documentation" below) might still show manually crafted JSON schemas. The recommended approach is now to use Zod with automatic Fastify validation as shown above.
227+
114228
## Example: Logout Route Documentation
115229

116230
The logout route (`/api/auth/logout`) demonstrates proper documentation:

services/backend/GLOBAL_SETTINGS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,16 @@ When the server starts:
692692
| `github.oauth.callback_url` | `'http://localhost:3000/api/auth/github/callback'` ||| OAuth callback URL |
693693
| `github.oauth.scope` | `'user:email'` ||| OAuth requested scopes |
694694

695+
#### Global Settings (Group ID: `global`)
696+
697+
| Key | Default | Required | Encrypted | Description |
698+
|-----|---------|----------|-----------|-------------|
699+
| `global.page_url` | `'http://localhost:5173'` ||| Base URL for the application frontend |
700+
| `global.send_mail` | `'false'` ||| Enable or disable email sending functionality |
701+
| `global.enable_login` | `'true'` ||| Enable or disable all login functionality |
702+
| `global.enable_email_registration` | `'true'` ||| Enable or disable email registration |
703+
| `global.enable_swagger_docs` | `'true'` ||| Enable or disable Swagger API documentation endpoint (/documentation) |
704+
695705
### Helper Methods
696706

697707
The system provides helper methods for retrieving complete configurations:

0 commit comments

Comments
 (0)