Building REST APIs
Documenting APIs with OpenAPI
আপনি একটি free preview lesson দেখছেন।
আমরা এখন পর্যন্ত আমাদের HTTP API-এর প্রায় পুরো public contract design করেছি।
আমাদের endpoints:
/api/v1/products
/api/v1/inventory
/api/v1/orders
আমরা define করেছি:
HTTP methods
request DTOs
response DTOs
status codes
validation
pagination
error format
API versioning
এখন প্রশ্ন হলো:
অন্য একজন engineer কীভাবে এই contract বুঝবে?
শুধু Controller code পড়ে?
Confluence page পড়ে?
Slack message খুঁজে?
Frontend source code inspect করে?
Production-quality API-এর জন্য contract এমন format-এ describe করা দরকার যা:
মানুষ পড়তে পারে
tooling বুঝতে পারে
documentation generate করা যায়
client generation করা যায়
contract review করা যায়
OpenAPI এই problem solve করার জন্য একটি standard API description format। OpenAPI Specification HTTP API-কে language-independent machine-readable contract হিসেবে describe করে; current published specification হলো OpenAPI 3.2.0।
এই lesson-এর goal:
আমাদের
/api/v1HTTP contract-কে OpenAPI দিয়ে document করা—without letting documentation annotations become the source of business behaviour.
OpenAPI Is a Contract Description
Suppose we have:
POST /api/v1/orders
A developer needs to know:
What request body is accepted?
Which fields are required?
What does success return?
What does 400 mean?
What does 404 mean?
What does 409 mean?
Is authentication required?
What error shape is returned?
OpenAPI lets us describe all of that in one structured specification।
Conceptually:
paths:
/api/v1/orders:
post:
...
OpenAPI Is Not Swagger UI
These terms are often mixed together।
They are different concepts।
OpenAPI
→ API description specification
A UI such as Swagger UI or Scalar can render an OpenAPI document into interactive documentation।
Spring tooling such as springdoc-openapi can inspect Spring Boot MVC configuration and annotations to generate an OpenAPI document; its official documentation describes generated JSON API descriptions and interactive UI integrations.
Think:
Spring Controllers + DTOs + metadata
↓
OpenAPI document
↓
documentation UI
The OpenAPI document is the important contract artifact।
The UI is one way to view it।
What OpenAPI Can Describe
Our specification can describe:
API information
paths
HTTP methods
path parameters
query parameters
request bodies
response bodies
schemas
HTTP status codes
authentication requirements
error responses
These concepts are defined directly by the OpenAPI Specification.
Start With API Information
An OpenAPI document begins with basic metadata।
Conceptually:
openapi: 3.2.0
info:
title: Order Management API
version: 1.0.0
description: >
HTTP API for product browsing,
inventory management,
order workflows,
and payment operations.
Notice:
info.version
is document/API metadata।
It should not be confused with:
/api/v1
route version semantics।
Avoid Confusing Three Versions
We may have:
OpenAPI specification version
→ 3.x
our public API major version
→ v1
application release version
→ whatever build is deployed
These are separate concerns।
Paths
Our current public API direction can be represented as:
paths:
/api/v1/products:
get:
...
post:
...
/api/v1/products/{productId}:
get:
...
patch:
...
/api/v1/products/{productId}/deactivate:
post:
...
/api/v1/inventory:
get:
...
/api/v1/inventory/{productId}:
get:
...
put:
...
/api/v1/orders:
get:
...
post:
...
/api/v1/orders/{orderId}:
get:
...
/api/v1/orders/{orderId}/cancel:
post:
...
/api/v1/orders/{orderId}/pay:
post:
...
This is valuable because the complete HTTP surface becomes visible without reading Java implementation।
Path Parameters
For:
GET /api/v1/orders/{orderId}
OpenAPI should describe:
parameters:
- name: orderId
in: path
required: true
schema:
type: string
We currently know:
OrderId is represented as a string at the HTTP boundary
but we have not finalized a UUID/prefix/numeric format।
Therefore documentation should not invent:
format: uuid
unless that decision is actually made।
Documentation Must Follow the Contract
This principle matters:
OpenAPI describes decisions. It should not silently make decisions for us.
If ProductId format is not decided:
type: string
is enough।
Do not add a regex simply because OpenAPI supports patterns।
Request Body
Our Create Product request:
{
"name": "Mechanical Keyboard",
"price": 100.00
}
can be described conceptually as:
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateProductRequest"
Then:
components:
schemas:
CreateProductRequest:
type: object
required:
- name
- price
properties:
name:
type: string
price:
type: number
The schema describes the public request contract।
Request Schema Should Match Authority
Our Order creation schema should not contain:
customerId
status
unitPrice
total
because the client does not control them।
Correct conceptual schema:
CreateOrderRequest:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
items:
$ref: "#/components/schemas/CreateOrderItemRequest"
and:
CreateOrderItemRequest:
type: object
required:
- productId
- quantity
properties:
productId:
type: string
quantity:
type: integer
minimum: 1
OpenAPI documentation should reinforce the same server-authority boundary as our DTO design।
Do Not Document Fields the Client Cannot Send
Bad OpenAPI:
CreateOrderRequest:
properties:
customerId:
type: string
status:
type: string
total:
type: number
even if implementation ignores them।
Documentation would tell clients:
These are valid request fields.
That creates a misleading contract।
Documentation and implementation must agree।
Response Schemas
Our Order response conceptually contains:
{
"id": "O-1001",
"status": "UNPAID",
"items": [
{
"productId": "P-100",
"quantity": 2,
"unitPrice": 20.00,
"total": 40.00
}
],
"total": 40.00
}
We can describe:
OrderResponse:
type: object
required:
- id
- status
- items
- total
properties:
id:
type: string
status:
type: string
enum:
- UNPAID
- PAID
- CANCELLED
items:
type: array
items:
$ref: "#/components/schemas/OrderItemResponse"
total:
type: number
Now API consumers know exactly which lifecycle values currently exist।
Public Enums Deserve Care
Once OpenAPI says:
enum:
- UNPAID
- PAID
- CANCELLED
those values are visibly part of the contract।
That reinforces the versioning lesson:
Adding or changing enum semantics deserves compatibility review।
Documentation makes implicit coupling visible।
Reusable Schemas
Instead of redefining:
OrderResponse
inside every endpoint, OpenAPI allows reusable components।
Conceptually:
components:
schemas:
OrderResponse:
...
Then:
$ref: "#/components/schemas/OrderResponse"
can be reused across:
create Order
get Order
cancel Order
pay Order
if those operations intentionally return the same representation।
Reuse Only When Contracts Are Actually the Same
Do not reuse one giant:
OrderDto
simply to reduce OpenAPI YAML।
If:
GET /orders
eventually returns OrderSummaryResponse
while:
GET /orders/{id}
returns detailed OrderResponse,
document them separately।
OpenAPI reuse should reflect semantic reuse, not force it।
Success Responses
Create Order:
responses:
"201":
description: Order created
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
We can also document:
Location
response header because successful creation may identify:
/api/v1/orders/{orderId}
GET Response
For:
GET /api/v1/orders/{orderId}
documentation can say:
"200":
description: Order returned successfully
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
This defines observable behaviour, not implementation details।
Document Expected Errors
A professional specification should not document only:
200
201
Expected failures are equally important।
For Order creation we currently have meaningful cases such as:
400 → invalid request
401 → authentication required
404 → Product missing
409 → Product not orderable / insufficient Inventory
500 → unexpected server failure
These belong in API documentation।
Our Canonical Problem Schema
Our LiveKlass problem response has:
type
title
status
detail
instance
code
errors?
Conceptually:
ApiProblem:
type: object
required:
- type
- title
- status
- detail
- instance
- code
properties:
type:
type: string
format: uri
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
code:
type: string
errors:
type: array
items:
$ref: "#/components/schemas/FieldProblem"
FieldProblem
FieldProblem:
type: object
required:
- field
- code
- message
properties:
field:
type: string
code:
type: string
message:
type: string
This matches our canonical API contract।
Validation Problem Example
OpenAPI can include an example:
example:
type: https://api.liveklass.io/problems/validation-error
title: Validation failed
status: 400
detail: One or more fields are invalid.
instance: /api/v1/orders
code: VALIDATION_ERROR
errors:
- field: items[0].quantity
code: INVALID_VALUE
message: Quantity must be greater than 0.
Examples are valuable because a schema tells clients:
what can exist
while an example shows:
what a real response looks like
Reusable Error Responses
Because many endpoints return the same broad problem schema, we can reuse response components।
Conceptually:
components:
responses:
ValidationError:
description: Request validation failed
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
Likewise:
Unauthorized
Forbidden
InternalError
can potentially share reusable definitions।
Don't Over-Generalize Business Errors
We could create one generic:
ConflictError
for every 409।
But clients still need to understand:
INSUFFICIENT_INVENTORY
versus:
ORDER_NOT_CANCELLABLE
The body schema may be shared, while operation descriptions/examples document the possible application code values।
Document Error Codes
For:
POST /api/v1/orders/{orderId}/cancel
a 409 response should document possible:
ORDER_NOT_CANCELLABLE
rather than merely:
409 Conflict
This makes our machine-readable error vocabulary discoverable।
Pagination Parameters
Our current pagination contract:
page
→ default 0
→ minimum 0
size
→ default 20
→ minimum 1
→ maximum 100
OpenAPI should describe exactly that।
Conceptually:
parameters:
- name: page
in: query
required: false
schema:
type: integer
minimum: 0
default: 0
- name: size
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
Now clients don't need to guess pagination rules।
Paginated Response
Our page envelope:
{
"items": [],
"page": 0,
"size": 20,
"totalItems": 0,
"totalPages": 0
}
should also have an explicit schema।
For Product:
ProductPageResponse:
type: object
required:
- items
- page
- size
- totalItems
- totalPages
properties:
items:
type: array
items:
$ref: "#/components/schemas/ProductResponse"
page:
type: integer
size:
type: integer
totalItems:
type: integer
format: int64
totalPages:
type: integer
Generic Concepts vs Concrete OpenAPI Schemas
In Java we might eventually use:
PageResponse<T>
But generated OpenAPI needs concrete schemas consumers can understand, such as:
ProductPageResponse
OrderPageResponse
Tooling may generate these from generic Java models, but we should review the resulting contract rather than assume generic inference is perfect।
Authentication Documentation
Our protected endpoints eventually require authenticated identity।
OpenAPI supports reusable security schemes for documenting how operations are authenticated.
Conceptually, if the application uses Bearer token authentication:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
Then an operation can declare:
security:
- bearerAuth: []
Do Not Invent Authentication Details
We know our application uses an existing identity mechanism and eventually Spring Security।
But exact token details should reflect the real authentication contract।
Do not document:
JWT claims
issuer
OAuth flow
token URL
unless those are actual decisions।
OpenAPI documentation must describe reality।
Authentication vs Authorization Documentation
Security scheme can communicate:
authentication required
But role requirements also matter։
For example:
POST /products
→ ADMIN only
Operation description should make that clear।
Likewise:
POST /orders
→ authenticated CUSTOMER
and:
GET own Order
→ ownership enforced
OpenAPI cannot replace our authorization implementation, but it should communicate the intended contract।
Don't Put customerId Back Into the API Documentation
Because authentication owns customer identity, this would be wrong:
parameters:
- name: customerId
in: query
for customer Order history।
Correct documentation:
GET /api/v1/orders
returns Orders scoped to the authenticated customer।
That security rule is part of endpoint description, not a caller-controlled filter।
Operation IDs
OpenAPI operations can have stable identifiers such as:
operationId: createOrder
or:
operationId: cancelOrder
These can be useful for:
documentation
client generation
tooling
Use meaningful names that represent application operations।
Avoid auto-generated names such as:
postUsingPOST_3
if we have control over them।
Operation Summary and Description
Good documentation:
summary: Create an order
description: >
Creates an unpaid order for the authenticated customer
using current server-side product prices.
Inventory is consumed as part of successful creation.
This communicates meaningful behaviour।
Documentation Should Explain Important Semantics
For Order creation, useful documentation includes:
authenticated Customer owns the Order
client price is ignored/not accepted
server uses current Product price
duplicate Product IDs are invalid
successful creation consumes Inventory
operation is all-or-nothing
These behaviours are far more valuable than repeating:
POST means POST.
Don't Turn OpenAPI Into an RFC
However, OpenAPI is not the place for the entire technical design।
It should not contain long explanations about:
why we chose modular monolith
why Inventory is separate from Product
transaction implementation details
JPA mapping strategy
database indexes
Those belong in:
RFCs
ADRs
technical documentation
OpenAPI documents the client-facing contract।
OpenAPI vs RFC
Think:
RFC
→ why/how we designed the system
OpenAPI
→ what HTTP clients can rely on
Both matter।
They solve different documentation problems।
Code-First Documentation
With Spring Boot, one approach is:
Controller + DTOs + annotations
↓
OpenAPI generation
springdoc-openapi is designed to generate OpenAPI descriptions from Spring Boot applications by examining Spring configuration and annotations.
This is often called a code-first approach।
Contract-First Documentation
Another approach:
OpenAPI YAML
↓
implementation
where specification is designed first and code follows it।
This can be valuable when:
multiple teams integrate independently
clients are generated before implementation
API governance is strict
Which Approach Are We Using?
Our course workflow already does:
Requirement
↓
RFC / API design
↓
engineering tickets
↓
implementation
So conceptually we are contract-driven।
But in the Spring project, we can use springdoc-openapi to generate the machine-readable specification from our actual Controllers/DTOs plus explicit documentation metadata।
The important part is not whether the YAML or Java file was typed first।
The important part is:
The reviewed API design and generated documentation must agree.
Generated Does Not Mean Correct
Suppose tooling sees:
public OrderResponse create(...) {
}
It may infer a response schema।
But tooling cannot automatically know all business semantics such as:
409 means INSUFFICIENT_INVENTORY
Customer can only read own Orders
Product deactivation preserves historical Orders
We still need intentional documentation।
Annotation Explosion
A Controller can become difficult to read if every method contains dozens of documentation annotations।
For example conceptually:
@Operation(...)
@ApiResponses(...)
@RequestBody(...)
@Parameter(...)
@Schema(...)
...
Documentation metadata has value, but Controller readability also matters।
Use annotations where they provide real contract information, and place reusable schema information on DTOs/configuration where appropriate।
Do not turn Handler logic into an OpenAPI wall।
Springdoc Metadata
Springdoc supports supplementing generated descriptions with OpenAPI/Swagger annotations, and can derive information from Spring application structure.
Conceptually:
@Operation(
summary = "Create an order"
)
@PostMapping
public ...
can improve generated operation documentation।
DTO Schema Metadata
If a field meaning isn't obvious:
@Schema(
description =
"Quantity of the product to order"
)
Integer quantity
may help।
But avoid redundant annotations like:
description = "The quantity field"
Good documentation explains semantics, not syntax already visible from the schema।
Examples Can Be More Valuable Than Descriptions
For ProductId:
example = P-100
can make docs easier to understand।
For validation problem:
VALIDATION_ERROR
with nested field errors is especially useful as a complete example।
Examples should be realistic but not mistaken for fixed business values।
Avoid Fake Requirements in Examples
If we show:
maximumQuantity = 10
in a schema example, students/consumers may infer it is an actual rule।
Our current requirements do not define a maximum order quantity।
Examples should not accidentally become shadow requirements।
Document Content Types
Successful JSON API responses use:
application/json
Our canonical error documents use:
application/problem+json
Documenting both makes the contract more precise।
Complete Conceptual Order Endpoint
A simplified OpenAPI fragment might look like:
paths:
/api/v1/orders:
post:
operationId: createOrder
summary: Create an order
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrderRequest"
responses:
"201":
description: Order created
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"400":
description: Request validation failed
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
"401":
description: Authentication required
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
"404":
description: A referenced product could not be found
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
"409":
description: >
Order creation conflicts with current
product or inventory state
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
"500":
description: Unexpected server failure
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiProblem"
This already tells another engineer a lot about the operation।
But 409 Still Needs Application Meaning
The specification should also explain possible code values such as:
PRODUCT_NOT_ORDERABLE
INSUFFICIENT_INVENTORY
Otherwise a client only knows:
some conflict happened
Our custom code field is part of the public contract and should be documented intentionally।
Product Endpoint Example
POST /api/v1/products
should document:
201 PRODUCT CREATED
400 VALIDATION_ERROR / INVALID_REQUEST
401 AUTHENTICATION_REQUIRED
403 ACCESS_DENIED
500 INTERNAL_ERROR
No:
customerId
No invented Inventory initialization।
OpenAPI should reflect our accepted business contract exactly।
Inventory Endpoint Example
For:
PUT /api/v1/inventory/{productId}
document:
availableQuantity
→ required
→ integer
→ minimum 0
And expected responses:
200
400 VALIDATION_ERROR
401
403
404
500
Again, no speculative:
inventory movement history
warehouse ID
adjustment reason
because those features don't exist।
Cancellation Endpoint Example
For:
POST /api/v1/orders/{orderId}/cancel
the most valuable documentation is not the empty request body।
It is the behaviour:
only authenticated owner may cancel
only UNPAID Order may cancel
successful cancellation restores Inventory
PAID/CANCELLED conflict returns
ORDER_NOT_CANCELLABLE
This is what consumers need to integrate correctly।
Payment Documentation Is Intentionally Incomplete
We already know:
POST /api/v1/orders/{orderId}/pay
exists conceptually।
But the exact Payment Provider contract is deferred।
Therefore don't invent OpenAPI request fields such as:
cardNumber
paymentMethodToken
providerSessionId
until integration requirements are known।
OpenAPI documentation should remain honest about what is actually designed।
OpenAPI Is Executable Documentation, Not Truth by Magic
A generated document can still be wrong।
Examples:
Controller accepts field but docs hide it
docs say 404 but runtime returns 500
docs say max size 100 but implementation allows 1000
error schema says application/json
but runtime returns something else
The specification becomes useful only if we keep it aligned with implementation।
Contract Tests Help
Important API behaviour can be verified through tests:
route exists
request validation matches docs
response shape matches DTO
status codes match contract
error structure matches ApiProblem
We don't need to test every generated OpenAPI byte।
But contract-critical behaviour should be protected।
OpenAPI Validation in CI
As the project matures, CI can:
generate OpenAPI
validate specification
compare important contract changes
Potential breaking changes can then be reviewed deliberately।
We do not need to build sophisticated API governance infrastructure in the first ticket।
But OpenAPI gives us the artifact needed for that later։
Generated Client Code
A machine-readable OpenAPI contract can also be used by tooling to generate client code because the specification exposes paths and schemas in a language-independent format.
This can reduce duplicated handwritten client models।
But generated clients are only as good as the specification।
Poor schema:
object
everywhere produces poor clients।
Strong explicit DTOs produce stronger generated contracts।
OpenAPI Should Not Dictate Domain Design
Avoid reasoning:
OpenAPI generated this schema, so our Order domain must match it.
Direction remains:
Requirements
↓
Domain / API design
↓
Implementation
↓
OpenAPI representation
Not:
Documentation generator
↓
Domain architecture
Exposing OpenAPI in Production
Whether interactive documentation endpoints are publicly accessible in production is an operational/security decision।
The machine-readable API description may be useful internally, publicly, or behind access controls depending on product needs।
Do not assume:
Swagger/Scalar UI must always be public in production
because a dependency makes it available locally।
Environment exposure should be deliberate।
Local Development Experience
For developers, interactive documentation can be extremely useful:
inspect endpoints
inspect schemas
see examples
try requests
Springdoc currently provides generated OpenAPI endpoints and supports interactive documentation integrations for Spring Boot applications.
This can make local development and frontend integration easier।
Don't Replace Automated Tests With "Try It"
Interactive API documentation is useful for exploration।
It does not replace:
unit tests
integration tests
contract tests
Clicking an endpoint successfully once does not prove:
validation
authorization
concurrency
error cases
work correctly।
Don't Replace Requirements With OpenAPI Either
OpenAPI can say:
quantity minimum = 1
But the reason this rule exists comes from requirements/domain design।
The specification captures the contract after the decision।
It doesn't replace the engineering reasoning behind it।
Documentation Quality Checklist
For each operation, ask:
Is the HTTP method and path documented?
Are all path/query parameters documented?
Is the request body schema accurate?
Are required fields correct?
Are server-controlled fields absent from request schemas?
Is the success status documented?
Is the success response schema documented?
Are expected 4xx outcomes documented?
Is the canonical ApiProblem schema used?
Are meaningful application error codes documented?
Is authentication requirement visible?
Are authorization/ownership semantics explained?
Are pagination defaults and limits documented?
Have we avoided documenting features
that do not actually exist?
Common Mistake 1 — Swagger UI Is Treated as OpenAPI
The specification is the contract; interactive UI is a renderer/consumer of that contract।
Common Mistake 2 — Only Success Responses Are Documented
Expected client and business failures are part of the API too।
Common Mistake 3 — Generic object Schemas
Clients cannot understand or generate useful types from vague contracts।
Common Mistake 4 — Request Schema Mirrors Domain Entity
Server-controlled fields accidentally become documented client input।
Common Mistake 5 — JPA Entity Generates Public Schema
Persistence implementation leaks into API documentation।
Common Mistake 6 — Documentation Invents Rules
Don't add arbitrary ID patterns, quantity limits, search filters, or Payment fields just to make the schema look complete।
Common Mistake 7 — Pagination Is Undocumented
Clients then guess default size, maximum size, and page numbering।
Common Mistake 8 — Error Body Is Documented as "string"
Our canonical Problem Details contract deserves a real schema।
Common Mistake 9 — Authentication Requirement Is Missing
Clients should know which operations require identity and permissions।
Common Mistake 10 — Generated Documentation Is Never Reviewed
Automation reduces manual work; it does not guarantee semantic correctness।
Our OpenAPI Documentation Direction
For the v1 API we will document:
/api/v1/products
/api/v1/inventory
/api/v1/orders
including:
request schemas
response schemas
page/size pagination
authentication requirements
authorization expectations
HTTP statuses
canonical application/problem+json errors
stable application error codes
We will not document speculative:
Customer CRUD
OrderItem CRUD
Product delete
Product reactivation
warehouse management
Inventory reservations
refunds
Payment Provider request fields
search/filter combinations not yet required
Responsibility Map
API Design
Decides:
what the client contract should be
Handler and DTOs
Implement:
that transport contract
OpenAPI
Describes:
that contract in machine-readable form
Tests
Verify:
runtime behaviour still follows the contract
RFCs and ADRs
Explain:
why important design choices were made
These artifacts complement each other।
They are not replacements for each other।
Engineering Principle
The core principle:
OpenAPI documents the contract consumers can rely on; it should not expose or dictate the implementation behind that contract.
Another:
Generated documentation still requires engineering judgment—tools can discover structures, but they cannot decide our business semantics for us.
And:
An API is not fully documented if only successful requests are described; validation, authentication, business conflicts, pagination, and error codes are part of the contract too.
Summary
In this lesson, we learned that:
- OpenAPI provides a language-independent machine-readable description of an HTTP API.
- OpenAPI and interactive documentation tools such as Swagger UI or Scalar are different concepts.
- Our public API is versioned under
/api/v1. - OpenAPI should document paths, methods, parameters, bodies, responses, schemas, and security requirements.
- Request schemas must contain only fields callers are legitimately allowed to provide.
CreateOrderRequestmust not exposecustomerId, price, total, or status.- Response schemas can describe server-controlled state such as Order status and purchase-time prices.
- Reusable schemas belong under OpenAPI components when contracts genuinely match.
- Public enum values should be documented intentionally because consumers may depend on them.
- Successful creation should document
201, the response model, and where appropriate theLocationheader. - Expected
400,401,403,404,409, and500responses should also be documented. - Our canonical
ApiProblemcontainstype,title,status,detail,instance,code, and optionalerrors. - Validation field errors contain
field,code, andmessage. - Error responses use
application/problem+json. - Application error codes such as
INSUFFICIENT_INVENTORYandORDER_NOT_CANCELLABLEshould be visible in the API contract. - Pagination documentation must define
page,size, defaults, bounds, and page response metadata. - Authentication can be represented through an OpenAPI security scheme while authorization semantics still need clear operation documentation.
- Customer ownership must not become a caller-controlled
customerIdquery parameter. - OpenAPI documentation is different from an RFC: OpenAPI describes what clients can rely on; RFCs explain engineering decisions.
springdoc-openapican generate OpenAPI descriptions from Spring Boot applications and enrich them with metadata.- Generated documentation must still be reviewed because tooling cannot infer every business rule.
- OpenAPI should not expose persistence entities or dictate domain design.
- We should not document speculative functionality merely to make the API appear comprehensive.
- Tests should protect the runtime contract represented by the documentation.
This completes:
Module 5 — Building REST APIs
We now have the HTTP foundation needed to move from API design into persistence.
Next:
Module 6 — Persistence with PostgreSQL
Lesson 1: Why Our Application Needs Persistence
There we will examine what state our Order Management Backend must preserve, why in-memory Java objects are insufficient, what PostgreSQL is responsible for, and—equally important—what responsibilities do not belong to the database.