OpenAPI Generator Server Generation: Build API Server Stubs from Specs
In this tutorial, you will learn about OpenAPI Generator Server Generation: Build API Server Stubs from Specs. We cover key concepts, practical examples, and best practices to help you master this topic.
Server generation creates stub code for implementing API backends from OpenAPI specs, providing controllers, models, serialization, validation, and routing for frameworks like Flask, Express, Spring, and Gin.
What You'll Learn
How to generate server stubs for multiple frameworks (Python Flask/FastAPI, Node.js Express, Java Spring Boot, Go Gin), implement handler logic, configure model serialization, add validation, and test the generated server.
Why It Matters
Server stub generation provides a spec-compliant starting point with routing, models, and validation pre-configured. DodaTech generates Spring Boot stubs from specs, reducing API implementation time by 60%.
Real-World Use
The DodaTech team adds a new Orders API. They write the OpenAPI spec, generate a Spring Boot server stub, implement the business logic in the generated controller interfaces, and deploy — all within 2 hours instead of 2 days.
flowchart LR
A["OpenAPI\nSpec"] --> B["Server\nGenerator"]
B --> C["Python\nFlask/FastAPI"]
B --> D["Node.js\nExpress"]
B --> E["Java\nSpring Boot"]
B --> F["Go\nGin/Echo"]
C --> G["Implement\nControllers"]
D --> G
E --> G
F --> G
G --> H["Working\nAPI Server"]
style A fill:#6cb4ee,color:#fff
style H fill:#bbf7d0,stroke:#16a34a
Generating Python Flask Server
# Generate Python Flask server
openapi-generator generate \
-i openapi.yaml \
-g python-flask \
-o ./server-python \
--additional-properties=packageName=dodatech_api
# Generated structure:
# ./server-python/
# openapi_server/
# controllers/ # Stub controllers to implement
# models/ # Data models (auto-generated)
# openapi/ # Original spec copy
# encoder.py
# util.py
# requirements.txt
# setup.py
# Generated controller stub (openapi_server/controllers/user_controller.py)
import connexion
from typing import Any
from openapi_server.models.user import User
from openapi_server.models.error import Error
def create_user(body: User) -> tuple[User, int]:
"""Create a new user.
Implement this function with your business logic.
"""
# TODO: Implement user creation
# 1. Validate input
# 2. Save to database
# 3. Return created user
return body, 201
def get_user(user_id: int) -> tuple[User | Error, int]:
"""Get user by ID."""
# TODO: Implement
# user = db.session.get(User, user_id)
# if user:
# return user, 200
return Error(message="User not found"), 404
def list_users(limit: int = 20, offset: int = 0) -> tuple[list[User], int]:
"""List users with pagination."""
# TODO: Implement
# users = db.session.query(User).limit(limit).offset(offset).all()
# return users, 200
return [], 200
Generating Node.js Express Server
# Generate Express server
openapi-generator generate \
-i openapi.yaml \
-g nodejs-express-server \
-o ./server-node \
--additional-properties=serverPort=8080
// Generated controller (controllers/UserController.js)
'use strict';
const utils = require('../utils/writer.js');
const User = require('../service/UserService');
module.exports.createUser = function createUser(req, res, next) {
const body = req.swagger.params.body.value;
User.createUser(body)
.then((response) => {
utils.writeJson(res, response, 201);
})
.catch((error) => {
utils.writeJson(res, { message: error.message }, error.status || 500);
});
};
module.exports.getUser = function getUser(req, res, next) {
const userId = req.swagger.params.userId.value;
User.getUser(userId)
.then((response) => {
if (response) {
utils.writeJson(res, response);
} else {
utils.writeJson(res, { message: 'Not found' }, 404);
}
})
.catch((error) => {
utils.writeJson(res, { message: error.message }, 500);
});
};
Generating Java Spring Boot Server
# Generate Spring Boot server
openapi-generator generate \
-i openapi.yaml \
-g spring \
-o ./server-java \
--additional-properties=\
useSpringBoot3=true,\
useJakartaEe=true,\
apiPackage=com.dodatech.api,\
modelPackage=com.dodatech.model
// Generated controller interface (com/dodatech/api/UsersApi.java)
package com.dodatech.api;
import com.dodatech.model.User;
import com.dodatech.model.Error;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1")
public interface UsersApi {
@PostMapping("/users")
ResponseEntity<User> createUser(@RequestBody User body);
@GetMapping("/users/{userId}")
ResponseEntity<User> getUser(@PathVariable Long userId);
@GetMapping("/users")
ResponseEntity<List<User>> listUsers(
@RequestParam(defaultValue = "20") Integer limit,
@RequestParam(defaultValue = "0") Integer offset
);
}
// Implementation (com/dodatech/api/UsersApiController.java)
@RestController
public class UsersApiController implements UsersApi {
@Autowired
private UserRepository userRepository;
@Override
public ResponseEntity<User> createUser(User body) {
User user = userRepository.save(body);
return ResponseEntity.status(201).body(user);
}
@Override
public ResponseEntity<User> getUser(Long userId) {
return userRepository.findById(userId)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@Override
public ResponseEntity<List<User>> listUsers(Integer limit, Integer offset) {
Pageable pageable = PageRequest.of(offset / limit, limit);
Page<User> users = userRepository.findAll(pageable);
return ResponseEntity.ok(users.getContent());
}
}
Common Mistakes
1. Implementing Logic in Generated Controllers
Generated files are overwritten on regeneration. Never modify generated controller stubs directly. Use Dependency Injection (Spring), service layers, or separate implementation files (Express services).
2. Not Configuring Model Serialization
Default serialization may expose internal field names or include null values. Configure JSON property naming, null handling, and date formats in generator options.
3. Ignoring Validation Annotations
Generated models include validation annotations (@NotNull, @Size, @Pattern). Don't remove them — they provide spec-compliant input validation. Add custom validation in the service layer.
4. Using Generated Code Without Customization
Generated stubs return placeholder data. Every endpoint must be implemented with real business logic, database access, and error handling before the server is usable.
5. Forgetting to Handle Errors
Generated controllers often return 500 for unhandled exceptions. Implement proper error handling: 400 for validation, 404 for not found, 409 for conflicts, 500 for server errors.
Practice Questions
- How do you implement generated controller stubs without losing changes?
- What validation does generated code provide?
- How do you configure server port and package names?
- What should you do before running the generated server?
Answers:
- Use the service/Repository Patternory" >}} pattern. Generated controllers call service interfaces. Implement service classes separately (not regenerated). Spring's @Service, Express's service/ directory, Flask's blueprint separation.
- Generated models include field validation: @NotNull, @Size, @Pattern (Java), pydantic validators (Python), Joi schemas (Node.js). These validate input against the OpenAPI spec automatically.
- Use CLI additional-properties:
--additional-properties=serverPort=8080,apiPackage=com.dodatech.api. Or set in the config YAML file. Each generator has its own options. - Validate the spec, install dependencies (pip install, npm install, mvn install), configure database connection, implement at least one controller, and run the server to verify it starts.
Challenge: Write an OpenAPI spec for a Blog API (6 endpoints, 4 models), generate server stubs for 2 frameworks (Python FastAPI and Java Spring Boot), implement all endpoints in one framework with an in-memory database, test with curl, and verify the second framework compiles.
FAQ
Mini Project
Write an OpenAPI spec for a Task Management API (8 endpoints, 5 models), generate Python FastAPI server stubs and Java Spring Boot stubs, implement all Python endpoints with SQLite database, start the server, test every endpoint with curl, and verify the generated Spring Boot project compiles.
What's Next
Client Generation — generate client SDKs for various platforms.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro