The Thought Process for Writing a CRUD API
A repeatable thought process for writing any CRUD API. Here is the step-by-step.
The Thought Process for Writing a CRUD API
A repeatable thought process for writing any CRUD API. Here is the step-by-step.
Step 1: Identify the Resource
What is the noun? Posts, users, comments. The resource is the thing you are CRUDing.
Step 2: Define the Schema
What fields does the resource have? What types? What constraints? What relationships (refs)? What indexes? What timestamps?
const postSchema = new mongoose.Schema({
title: { type: String, required: true, minlength: 3, maxlength: 200 },
body: { type: String, required: true },
authorId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
tags: [String]
}, { timestamps: true });
postSchema.index({ authorId: 1, createdAt: -1 });
Step 3: List the Endpoints
- GET /posts (list)
- POST /posts (create)
- GET /posts/:id (read)
- PATCH /posts/:id (update)
- DELETE /posts/:id (delete)
Step 4: Write the Validation Schemas
For create and update, write Zod schemas:
const createPostSchema = z.object({
title: z.string().min(3).max(200),
body: z.string().min(1),
tags: z.array(z.string()).optional()
});
Step 5: Write the Controller Functions
exports.createPost = asyncHandler(async (req, res) => {
const post = await Post.create({ ...req.body, authorId: req.user.userId });
res.status(201).json(post);
});
exports.getPost = asyncHandler(async (req, res) => {
const post = await Post.findById(req.params.id).populate('authorId', 'firstName lastName');
if (!post) throw new ApiError(404, 'Post not found');
res.json(post);
});
Step 6: Write the Router
router.use(auth);
router.get('/', controller.listPosts);
router.post('/', validate(createPostSchema), controller.createPost);
router.get('/:id', controller.getPost);
router.patch('/:id', validate(updatePostSchema), controller.updatePost);
router.delete('/:id', controller.deletePost);
Step 7: Mount the Router
app.use('/api/v1/posts', require('./routes/posts')).
Step 8: Handle Edge Cases
- Not found: throw new ApiError(404, 'Post not found').
- Not authorized: if (post.authorId.toString() !== req.user.userId) throw new ApiError(403, 'Not authorized').
- Validation: the validate middleware handles it.
- Duplicate: catch the 11000 error and return 409.
Step 9: Test the API
Use Jest and supertest. Test happy paths and error paths. Test auth, validation, not found, and conflict.
Step 10: Document the API
Use Swagger or Postman. Write the endpoint, input, output, status codes, and examples.
The Takeaway
The thought process for a CRUD API: identify the resource, define the schema, list the endpoints, write validation schemas, write controller functions, write the router, mount it, handle edge cases, test, and document. Repeat for each resource.
Identify the resource, define the schema, list the endpoints, write validation schemas, write controller functions, write the router, mount it, handle edge cases (not found, not authorized, duplicate), test, and document. Repeat for each resource.
GET /resource (list), POST /resource (create), GET /resource/:id (read), PATCH /resource/:id (update), DELETE /resource/:id (delete). Use plural nouns for the path. Version with /api/v1.
Not found: throw new ApiError(404, 'Resource not found'). Not authorized: compare the resource's owner to req.user.userId; throw 403 if they do not match. Validation: the validate middleware handles it. Duplicate: catch the 11000 error and return 409.
Validation is part of the API contract. Writing the schema first forces you to think about what input is valid. The controller then only runs with valid input. Order: schema, validation, controller, router, mount.
Use Jest and supertest. Test happy paths (create, read, update, delete) and error paths (validation, not found, not authorized, duplicate). Use a test database and clean between tests. Run tests in CI.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

