REST API Design with Genspark: Fully Automated from OpenAPI Specification to Implementation
📋 Table of Contents
- Introduction: The Importance of API Design
- Non-RESTful APIs Resulting from Manual Design
- Example 1: Automated OpenAPI Specification Generation
- Example 2: Full Automation of Endpoint Implementation
- Example 3: API Documentation and Test Code Generation
- Complete API Design Workflow
- Summary: A New Era of AI and API Design
Introduction: The Importance of API Design
REST APIs are **the most crucial interface** in modern web applications. Poor design can lead to difficulties in frontend development, performance issues, and decreased maintainability. APIs that disregard RESTful principles may require extensive revisions later.
By utilizing Genspark for API design, we can now consistently generate **OpenAPI specifications, endpoint implementations, documentation, and test code**.
Non-RESTful APIs Resulting from Manual Design
When designing APIs manually in the early stages of a project, we encountered the following issues:
Examples of Design Mistakes
- ❌
GET /api/deleteUser/:id- Deletion operation with GET method - ❌
POST /api/getUserData- Verb-based endpoint - ❌ All errors returning
200 OK - ❌ Inconsistent response formats across endpoints
- ❌ No pagination implemented
- ❌ No API documentation exists
As a result of proceeding with development while having these issues, confusion arose on the frontend, becoming a breeding ground for bugs.
Example 1: Automated OpenAPI Specification Generation
Here's an example where we asked Genspark to design the API for a blog system.
Request to Genspark
Please design a REST API for a blog system with the following requirements:
## Requirements
- Article CRUD
- Category management
- Comment functionality
- Like functionality
- Article search
## Constraints
- Adhere to RESTful design
- Output in OpenAPI 3.0 format
- Authentication is JWT Bearer
- Pagination required
- Unified error responses
## Output Format
OpenAPI Specification (YAML format)
Genspark generated a perfect OpenAPI specification (excerpt).
Generated OpenAPI Specification (Excerpt)
openapi: 3.0.0
info:
title: Blog API
version: 1.0.0
description: RESTful blog system API
servers:
- url: https://api.example.com/v1
description: Production server
paths:
/articles:
get:
summary: Get all articles
tags: [Articles]
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: category
in: query
schema:
type: string
- name: search
in: query
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Article'
pagination:
$ref: '#/components/schemas/Pagination'
post:
summary: Create a new article
tags: [Articles]
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateArticleRequest'
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/Article'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/articles/{id}:
get:
summary: Get article by ID
tags: [Articles]
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/Article'
'404':
$ref: '#/components/responses/NotFound'
put:
summary: Update article
tags: [Articles]
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateArticleRequest'
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/Article'
'404':
$ref: '#/components/responses/NotFound'
delete:
summary: Delete article
tags: [Articles]
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'204':
description: No content
'404':
$ref: '#/components/responses/NotFound'
/articles/{id}/like:
post:
summary: Like an article
tags: [Articles]
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
likes:
type: integer
components:
schemas:
Article:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
slug:
type: string
content:
type: string
categoryId:
type: string
format: uuid
authorId:
type: string
format: uuid
likes:
type: integer
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
Pagination:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
totalPages:
type: integer
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
Strengths of the OpenAPI Specification
- ✅ **RESTful Design:** Resource-oriented, appropriate HTTP method usage
- ✅ **Unified Response Format:** Consistency across all endpoints
- ✅ **Error Handling:** Appropriate status codes and error schemas
- ✅ **Pagination:** Support for large data volumes
- ✅ **Authentication/Authorization:** Security scheme definition
Example 2: Full Automation of Endpoint Implementation
Once the OpenAPI specification is finalized, the next step is implementation. We asked Genspark to "implement Express endpoints based on this OpenAPI specification."
Generated Endpoint Implementation (Excerpt)
// src/routes/articles.routes.js
const express = require('express');
const router = express.Router();
const articlesController = require('../controllers/articles.controller');
const authMiddleware = require('../middleware/auth');
const validateRequest = require('../middleware/validateRequest');
const { articleSchemas } = require('../schemas/article.schemas');
// GET /articles - Get article list
router.get('/',
validateRequest(articleSchemas.getArticles),
articlesController.getArticles
);
// POST /articles - Create article
router.post('/',
authMiddleware,
validateRequest(articleSchemas.createArticle),
articlesController.createArticle
);
// GET /articles/:id - Get article details
router.get('/:id',
validateRequest(articleSchemas.getArticleById),
articlesController.getArticleById
);
// PUT /articles/:id - Update article
router.put('/:id',
authMiddleware,
validateRequest(articleSchemas.updateArticle),
articlesController.updateArticle
);
// DELETE /articles/:id - Delete article
router.delete('/:id',
authMiddleware,
articlesController.deleteArticle
);
// POST /articles/:id/like - Like
router.post('/:id/like',
authMiddleware,
articlesController.likeArticle
);
module.exports = router;
// src/controllers/articles.controller.js
const articlesService = require('../services/articles.service');
const { NotFoundError, BadRequestError } = require('../utils/errors');
exports.getArticles = async (req, res, next) => {
try {
const { page = 1, limit = 20, category, search } = req.query;
const result = await articlesService.getArticles({
page: parseInt(page),
limit: parseInt(limit),
category,
search
});
res.json({
data: result.articles,
pagination: {
page: result.page,
limit: result.limit,
total: result.total,
totalPages: Math.ceil(result.total / result.limit)
}
});
} catch (error) {
next(error);
}
};
exports.createArticle = async (req, res, next) => {
try {
const userId = req.user.id; // authMiddleware sets this
const articleData = {
...req.body,
authorId: userId
};
const article = await articlesService.createArticle(articleData);
res.status(201).json({ data: article });
} catch (error) {
next(error);
}
};
exports.getArticleById = async (req, res, next) => {
try {
const { id } = req.params;
const article = await articlesService.getArticleById(id);
if (!article) {
throw new NotFoundError('Article not found');
}
res.json({ data: article });
} catch (error) {
next(error);
}
};
exports.updateArticle = async (req, res, next) => {
try {
const { id } = req.params;
const userId = req.user.id;
// Permission check
const article = await articlesService.getArticleById(id);
if (!article) {
throw new NotFoundError('Article not found');
}
if (article.authorId !== userId && req.user.role !== 'admin') {
throw new ForbiddenError('You can only update your own articles');
}
const updatedArticle = await articlesService.updateArticle(id, req.body);
res.json({ data: updatedArticle });
} catch (error) {
next(error);
}
};
exports.deleteArticle = async (req, res, next) => {
try {
const { id } = req.params;
const userId = req.user.id;
// Permission check
const article = await articlesService.getArticleById(id);
if (!article) {
throw new NotFoundError('Article not found');
}
if (article.authorId !== userId && req.user.role !== 'admin') {
throw new ForbiddenError('You can only delete your own articles');
}
await articlesService.deleteArticle(id);
res.status(204).send();
} catch (error) {
next(error);
}
};
exports.likeArticle = async (req, res, next) => {
try {
const { id } = req.params;
const userId = req.user.id;
const likes = await articlesService.likeArticle(id, userId);
res.json({ data: { likes } });
} catch (error) {
next(error);
}
};
Strengths of the Generated Code
- ✅ **Layer Separation:** Clear separation of routes, controllers, and services
- ✅ **Appropriate Error Handling:** Use of custom error classes
- ✅ **Permission Check:** Only own articles can be edited
- ✅ **Validation:** Request schema validation
- ✅ **Unified Response Format:** Consistency across all endpoints
Example 3: API Documentation and Test Code Generation
From the OpenAPI specification, we also had Swagger documentation and test code automatically generated.
1. Swagger UI Setup
// src/app.js
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./openapi.yaml');
const app = express();
// Swagger UI
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
// ...other middleware configurations
module.exports = app;
This allows interactive API documentation to be viewed at http://localhost:3000/api-docs.
2. Automated Test Code Generation
// tests/articles.test.js
const request = require('supertest');
const app = require('../src/app');
const { createTestUser, generateToken } = require('./helpers');
describe('Articles API', () => {
let authToken;
let userId;
beforeAll(async () => {
const user = await createTestUser();
userId = user.id;
authToken = generateToken(user);
});
describe('GET /articles', () => {
it('should return paginated articles', async () => {
const res = await request(app)
.get('/articles?page=1&limit=10')
.expect(200);
expect(res.body).toHaveProperty('data');
expect(res.body).toHaveProperty('pagination');
expect(Array.isArray(res.body.data)).toBe(true);
expect(res.body.pagination).toMatchObject({
page: 1,
limit: 10,
total: expect.any(Number),
totalPages: expect.any(Number)
});
});
it('should filter by category', async () => {
const res = await request(app)
.get('/articles?category=technology')
.expect(200);
res.body.data.forEach(article => {
expect(article.category).toBe('technology');
});
});
});
describe('POST /articles', () => {
it('should create a new article', async () => {
const newArticle = {
title: 'Test Article',
content: 'This is a test article content.',
categoryId: 'some-category-id'
};
const res = await request(app)
.post('/articles')
.set('Authorization', `Bearer ${authToken}`)
.send(newArticle)
.expect(201);
expect(res.body.data).toMatchObject({
id: expect.any(String),
title: newArticle.title,
content: newArticle.content,
authorId: userId
});
});
it('should return 401 without auth token', async () => {
const res = await request(app)
.post('/articles')
.send({ title: 'Test' })
.expect(401);
});
});
describe('PUT /articles/:id', () => {
it('should update own article', async () => {
const article = await createTestArticle(userId);
const updatedData = {
title: 'Updated Title'
};
const res = await request(app)
.put(`/articles/${article.id}`)
.set('Authorization', `Bearer ${authToken}`)
.send(updatedData)
.expect(200);
expect(res.body.data.title).toBe(updatedData.title);
});
it('should return 403 when updating others article', async () => {
const otherUser = await createTestUser();
const article = await createTestArticle(otherUser.id);
await request(app)
.put(`/articles/${article.id}`)
.set('Authorization', `Bearer ${authToken}`)
.send({ title: 'Hacked' })
.expect(403);
});
});
});
Complete API Design Workflow
Here's a summary of the complete API design workflow utilizing Genspark.
Step 1: Requirements Definition
- List required endpoints
- Organize resource structure
- Clarify authentication and authorization requirements
Step 2: OpenAPI Specification Generation
Request to Genspark:
"Please create an OpenAPI 3.0 specification with the following requirements"
+ Detailed list of requirements
Step 3: Specification Review and Revision
- Review the generated specification with the team
- Request revisions from Genspark as needed
- Reach agreement with the frontend team
Step 4: Implementation Generation
Request to Genspark:
"Please implement Express endpoints based on this OpenAPI specification"
+ Technology stack (Express, Prisma, etc.)
Step 5: Test Code Generation
Request to Genspark:
"Please generate Jest test code based on this OpenAPI specification"
Step 6: Documentation Publication
- Set up Swagger UI
- Publish API documentation
- Share with the frontend team
Summary: A New Era of AI and API Design
Genspark **consistently automates API design from specification to implementation, testing, and documentation**. A development flow centered around the OpenAPI specification has smoothed coordination between frontend and backend.
Outcomes of Genspark Utilization
- API Design Time: 2 days → half a day (4x faster)
- Implementation Time: 1 week → 2 days (3.5x faster)
- Specification-Implementation Discrepancy: Zero
- Documentation: Always up-to-date
Actions You Can Start Today
- ✅ Generate OpenAPI specifications for existing APIs
- ✅ Design new APIs with an OpenAPI-first approach
- ✅ Publish documentation with Swagger UI
- ✅ Automatically generate test code
API design is also entering a new era of collaboration with AI.