PromptBase
Upgrade
Close icon
General
Home
Marketplace
Create
Hire
Login
Chat
Sell
Explore

Skill Details

Runtime
(claude-4-6-sonnet)
Example user message
[userMessage]: Resource: Blog posts with title, content, author_id, published (boolean) Framework: Express with MongoDB (Mongoose) Operations: Full CRUD Validation: title required, content required, author_id required
Example agent response
STEP 1 — RESOURCE DESIGN Resource: post (singular model, plural route "posts") Fields: - title: String, required - content: String, required - author_id: ObjectId, required (reference to User) - published: Boolean, optional, default false - createdAt/updatedAt: auto-managed by Mongoose timestamps STEP 2 — ROUTE PLANNING GET /api/posts — list all posts Success: 200 with array Errors: 500 server error GET /api/posts/:id — get single post Success: 200 with post object Errors: 404 not found, 400 invalid ID format, 500 server error POST /api/posts — create post Body: {title, content, author_id, published?} Success: 201 with created post Errors: 400 validation failure, 500 server error PUT /api/posts/:id — full update Body: {title, content, author_id, published} Success: 200 with updated post Errors: 400 validation, 404 not found, 500 server error DELETE /api/posts/:id — delete post Success: 200 with confirmation message Errors: 404 not found, 500 server error STEP 3 — VALIDATION RULES - title: required, string, min 1 char, max 200 chars - content: required, string, min 1 char - author_id: required, valid MongoDB ObjectId format - published: optional, must be boolean if provided STEP 4 — COMPLETE ENDPOINT CODE ```javascript const express = require('express'); const router = express.Router(); const mongoose = require('mongoose'); const Post = require('../models/Post'); // Validation helper function validatePostInput(data, isPartial = false) { const errors = []; if (!isPartial || data.title !== undefined) { if (!data.title || typeof data.title !== 'string') { errors.push('title is required and must be a string'); } else if (data.title.length > 200) { errors.push('title must be 200 characters or less'); } } if (!isPartial || data.content !== undefined) { if (!data.content || typeof data.content !== 'string') { errors.push('content is required and must be a string'); } } if (!isPartial || data.author_id !== undefined) { if (!data.author_id || !mongoose.Types.ObjectId.isValid(data.author_id)) { errors.push('author_id is required and must be a valid ID'); } } if (data.published !== undefined && typeof data.published !== 'boolean') { errors.push('published must be a boolean'); } return errors; } // GET /api/posts - list all posts router.get('/posts', async (req, res) => { try { const posts = await Post.find().sort({ createdAt: -1 }); res.status(200).json({ data: posts }); } catch (error) { console.error('Error fetching posts:', error); res.status(500).json({ error: 'Failed to fetch posts' }); } }); // GET /api/posts/:id - get single post router.get('/posts/:id', async (req, res) => { try { const { id } = req.params; if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: 'Invalid post ID format' }); } const post = await Post.findById(id); if (!post) { return res.status(404).json({ error: 'Post not found' }); } res.status(200).json({ data: post }); } catch (error) { console.error('Error fetching post:', error); res.status(500).json({ error: 'Failed to fetch post' }); } }); // POST /api/posts - create post router.post('/posts', async (req, res) => { try { const errors = validatePostInput(req.body); if (errors.length > 0) { return res.status(400).json({ error: 'Validation failed', details: errors }); } const post = new Post({ title: req.body.title, content: req.body.content, author_id: req.body.author_id, published: req.body.published || false }); const savedPost = await post.save(); res.status(201).json({ data: savedPost }); } catch (error) { console.error('Error creating post:', error); res.status(500).json({ error: 'Failed to create post' }); } }); // PUT /api/posts/:id - full update router.put('/posts/:id', async (req, res) => { try { const { id } = req.params; if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: 'Invalid post ID format' }); } const errors = validatePostInput(req.body); if (errors.length > 0) { return res.status(400).json({ error: 'Validation failed', details: errors }); } const updatedPost = await Post.findByIdAndUpdate( id, { title: req.body.title, content: req.body.content, author_id: req.body.author_id, published: req.body.published }, { new: true, runValidators: true } ); if (!updatedPost) { return res.status(404).json({ error: 'Post not found' }); } res.status(200).json({ data: updatedPost }); } catch (error) { console.error('Error updating post:', error); res.status(500).json({ error: 'Failed to update post' }); } }); // DELETE /api/posts/:id - delete post router.delete('/posts/:id', async (req, res) => { try { const { id } = req.params; if (!mongoose.Types.ObjectId.isValid(id)) { return res.status(400).json({ error: 'Invalid post ID format' }); } const deletedPost = await Post.findByIdAndDelete(id); if (!deletedPost) { return res.status(404).json({ error: 'Post not found' }); } res.status(200).json({ message: 'Post deleted successfully' }); } catch (error) { console.error('Error deleting post:', error); res.status(500).json({ error: 'Failed to delete post' }); } }); module.exports = router; ``` STEP 5 — ERROR RESPONSE STANDARDIZATION Consistent shape: ```json { "error": "message", "details": [] } ``` Success shape: ```json { "data": {...} } ``` Status codes used: - 200: Successful GET/PUT/DELETE - 201: Successful POST (resource created) - 400: Validation failure or malformed ID - 404: Resource not found - 500: Unexpected server error Example error responses: Validation failure (400): ```json { "error": "Validation failed", "details": [ "title is required and must be a string", "author_id is required and must be a valid ID" ] } ``` Not found (404): ```json { "error": "Post not found" } ``` STEP 6 — SECURITY AND PRODUCTION NOTES Not implemented (must be added): 1. Authentication middleware — these routes have NO auth check. Anyone can create/edit/delete posts. Add JWT or session-based auth middleware before these routes. 2. Authorization — even with auth, you likely want to verify the requesting user matches author_id before allowing PUT/DELETE (users shouldn't edit others' posts). 3. Rate limiting — consider adding express-rate-limit to prevent abuse, especially on POST endpoint. 4. Input sanitization — while type validation exists, consider adding HTML sanitization on content field if it will be rendered as HTML (XSS prevention). 5. Pagination — GET /posts currently returns ALL posts with no limit. Add pagination (limit/skip or cursor-based) before this scales beyond a few hundred posts. Note: This provides complete CRUD logic and validation. Authentication, authorization, and infrastructure setup (database connection, environment config) require additional implementation specific to your application's auth strategy.
↗ Cursor Skill

Rest Api Endpoint Generator Agent

Add to Cart
Instant accessInstant access
Usage rightsCommercial use
Money-back guaranteeMoney‑back
By purchasing this skill, you agree to our terms of service
CLAUDE-4-6-SONNET
Tested icon
Guide icon
Free credits icon
A structured 6-step REST API endpoint generation agent for developers using Cursor. Analyzes your resource requirements, then generates complete CRUD endpoints with proper routing, validation, error handling, and status codes — following REST conventions and your framework's best practices. Works with Express, FastAPI, and Flask. Describe your resource and get production-ready endpoint code instantly.
...more
Added 2 weeks ago
Report
Browse Marketplace