Define the API rules clearly first, then let AI write the code.
In AI-assisted development, interface design is an area that easily “looks like it works, but gets increasingly messy over time.”
Ask AI to write a few APIs for you, and it might quickly generate:
/getUser
/createUser
/update_user
/delete-user
/userList
They all work functionally. But as the project continues to grow, you easily end up with:
Same resource, different naming
Same action, different HTTP methods
Same error, different response structures
Same pagination, different field names
Eventually, frontend developers, backend developers, testers, and even AI itself start guessing:
“How exactly should this API be called?”
What’s truly missing here is not coding ability, but:
A unified API contract.
📌 Technical Profile
RESTful API (Representational State Transfer Application Programming Interface)
Is a common network interface design style.
It emphasizes designing URLs around “resources” and expressing operations through HTTP methods.
For example:
GET /agents
POST /agents
GET /agents/12
PUT /agents/12
DELETE /agents/12
Here:
GET: Read a resourcePOST: Create a resourcePUT: Fully update a resourcePATCH: Partially modify a resourceDELETE: Delete a resource
And:
Contract First
Refers to:
Defining what the interface looks like first, then implementing the internal logic.
In other words, first determine:
What is the URL?
What is the HTTP method?
What are the input fields?
What are the output fields?
How are errors returned?
What are the status codes?
Then developers or AI implement the code according to this contract.
A Simple Analogy: An API Is Like a Restaurant Menu
You can think of a software interface as a restaurant’s menu.
The menu states:
Kung Pao Chicken
Price: 38 yuan
Spiciness: Medium
Portion: 1 serving
The customer doesn’t need to know:
Who the chef is
What brand the wok is
How the kitchen prep works
How much oil goes into the chicken
The customer only needs to know:
I order from the menu, and you serve me what’s on the menu.
APIs work the same way.
The frontend shouldn’t need to care about:
How the database is queried
How the Service is implemented
How the Repository is written
It only needs to know:
Request URL
Request method
Parameter format
Response result
Error format
So an API contract is like:
The menu a software system publishes to the outside world.
If the menu changed every day:
Yesterday it was "Kung Pao Chicken"
Today it's "Spicy Diced Chicken"
Tomorrow it becomes "Chicken Combo A"
Customers would be driven crazy — and the same goes for APIs.
1. The Core of RESTful: URLs Express “Resources,” HTTP Methods Express “Actions”
This is the most important concept to understand about RESTful.
Many projects start out writing things like this:
/getAgent
/createAgent
/updateAgent
/deleteAgent
This approach essentially:
Puts actions into the URL.
Whereas RESTful recommends:
GET /agents
POST /agents
PUT /agents/{agent_id}
DELETE /agents/{agent_id}
Because:
/agents
Represents the resource:
The Agent collection.
As for “read, create, update, delete” — that’s expressed by HTTP methods.
So the interface language becomes very unified:
Resource + HTTP Method
Instead of:
Resource + Custom Verb + Custom Naming Convention
2. Why Is This Rule Especially Important for AI Programming?
Human developers working in a project for a few years will gradually form habits.
But AI is different. Every time AI generates code, it is essentially reasoning from scratch:
What should this API be called?
Should this update use POST or PUT?
What does a successful deletion return?
What are the pagination fields called?
Without architectural rules, AI might generate the following the first time:
POST /createAgent
Next time it generates:
POST /agents/create
And the time after that:
POST /agent
All three sets of APIs work, but the project has already started to lose control.
So:
RESTful isn’t about pursuing “textbook beauty” — it’s about reducing AI’s room for free improvisation.
3. API Design Rules
3.1 Unified Resource Naming
Resource names should use:
Nouns
Plural form
Consistent naming style
For example:
/users
/agents
/tools
/documents
/knowledge-bases
Rather than:
/userList
/getAgents
/toolManage
/queryDocument
miniagent’s current backend APIs use clear resource-oriented paths.
For example, the main program uniformly registers:
app.include_router(
admin_agent_router,
prefix="/api/v1/admin/agents",
tags=["Admin - Agent"]
)
app.include_router(
admin_tool_router,
prefix="/api/v1/admin/tools",
tags=["Admin - Tool"]
)
app.include_router(
admin_document_router,
prefix="/api/v1/admin/documents",
tags=["Admin - Document"]
)
You can see the resource naming maintains:
/agents
/tools
/documents
/knowledge-bases
/prompts
/system-settings
Without stuffing actions like:
get
create
delete
update
into the URL.
3.2 HTTP Methods Express Actions
Take miniagent’s Agent management APIs as an example.
Read the list:
@router.get("")
async def list_agents(...):
Read a single Agent:
@router.get("/{agent_id}")
async def get_agent(...):
Create:
@router.post("")
async def create_agent(...):
Update:
@router.put("/{agent_id}")
async def update_agent(...):
Delete:
@router.delete("/{agent_id}")
async def delete_agent(...):
Combined together:
GET /api/v1/admin/agents
GET /api/v1/admin/agents/{agent_id}
POST /api/v1/admin/agents
PUT /api/v1/admin/agents/{agent_id}
DELETE /api/v1/admin/agents/{agent_id}
Even if you’ve never seen the miniagent codebase, you can basically guess what these APIs do.
This is what good API design brings:
Predictability.
3.3 Don’t Misuse PUT and PATCH
This is a place where AI gets very easily confused.
PUT typically means:
Update a resource.
For example:
PUT /agents/12
Means update the Agent with ID 12.
And PATCH means:
Partial Update
That is, only modifying part of the resource’s state.
miniagent has a very intuitive example:
@router.patch("/{agent_id}/toggle")
async def toggle_agent_active(...):
Here, it’s not resubmitting the entire Agent — it’s just:
Toggling whether the Agent is active.
So using PATCH is more semantically appropriate.
For beginners, you can start by remembering:
PUT → Update a resource
PATCH → Partial modification
3.4 RESTful Doesn’t Mean “Actions Must Never Appear in URLs”
Many people take RESTful to the other extreme after learning it:
Absolutely no actions should ever appear in URLs.
That’s actually unnecessary.
Some business operations are not simple CRUD.
CRUD stands for:
Create, Read, Update, Delete
For example:
/agents/{id}/toggle
Expresses:
Toggle the Agent’s state.
Or in the future there might be:
/documents/{id}/reindex
/tasks/{id}/cancel
/agents/{id}/run
These are essentially business commands.
The point is not to mechanically pursue “pure REST,” but rather:
Resource-oriented operations follow a unified paradigm, and special business actions have clear and stable naming rules.
3.5 A Contract Is More Than Just URLs
Many projects believe:
Once the URLs are unified, the API standards are complete.
That’s far from enough. A complete API contract should at least include:
Request path
HTTP method
Path parameters
Query parameters
Request Body
Response Body
HTTP Status Code
Error model
Where:
Path Parameter:
Path Parameter
For example:
/agents/{agent_id}
Query Parameter:
Query Parameter
For example:
/agents?page=1&page_size=20
Request Body:
Request Body
The data body sent by the client.
Response Body:
Response Body
The data body returned by the server.
HTTP Status Code:
HTTP Status Code
For example:
200 OK
201 Created
404 Not Found
409 Conflict
500 Internal Server Error
3.6 Query Parameters Must Also Be Unified
Suppose in one system you see:
?page=1&pageSize=20
In another API:
?pageIndex=1&limit=20
And in yet another:
?offset=0&size=20
Each one works.
But the problem is:
The frontend can never remember them all.
miniagent’s Agent list API uses:
page: int = Query(1, ge=1)
page_size: int = Query(20, ge=1, le=100)
And the pagination result is defined as:
class PageResult(BaseModel, Generic[T]):
total: int
page: int
page_size: int
data: List[T]
So the entire project can uniformly use:
page
page_size
total
data
Instead of reinventing pagination for every module.
3.7 API Responses Must Have a Unified “Envelope”
This is a very important part of Contract First.
The most easily lost scenario is:
User API returns:
{
"success": true,
"user": {}
}
Agent API returns:
{
"code": 0,
"result": {}
}
Knowledge base API returns:
{
"status": "ok",
"data": {}
}
The frontend has to handle each module differently.
This is:
API contract fragmentation.
miniagent defines a unified response model:
class ApiResponse(BaseModel, Generic[T]):
code: int = 200
message: str = "success"
data: Optional[T] = None
So successful responses can be uniformly:
{
"code": 200,
"message": "success",
"data": {}
}
When there’s no data, it can also be:
{
"code": 200,
"message": "success"
}
The most important value of this design isn’t saving a few lines of code.
It’s that:
The frontend only needs to learn the response protocol once.
3.8 HTTP Status Codes and Business Response Structures Should Each Serve Their Purpose
When miniagent creates an Agent:
@router.post(
"",
response_model=ApiResponse,
status_code=status.HTTP_201_CREATED
)
Here it uses:
201 Created
To indicate:
The server successfully created a new resource.
While read or update operations typically return:
200 OK
If the resource doesn’t exist, the global exception handler returns:
404
If it already exists:
409
For general bad requests:
400
For internal server errors:
500
miniagent has already uniformly mapped these error types in its global exception handler.
This essentially establishes:
Domain Exception
↓
Unified Exception Handler
↓
HTTP Status Code
↓
Unified ApiResponse
So the business layer doesn’t have to decide on its own:
Should I return 200?
Or 404?
What should the error JSON look like?
3.9 Contract First Truly Solves “Who Has the Final Say”
Without a contract, the development process easily becomes:
Frontend thinks it should be this way
↓
Backend writes it another way
↓
AI generates a third version
↓
Fix during integration testing
With Contract First, it becomes:
Define the API first
↓
Determine the inputs
↓
Determine the outputs
↓
Determine the status codes
↓
Frontend implements
↓
Backend implements
↓
Automated testing
The API becomes:
A protocol that both frontend and backend jointly follow.
3.10 FastAPI Is Naturally Suited for Contract First
FastAPI is:
A framework for building Web APIs based on Python type annotations.
One of its important features is:
It can directly generate API documentation from the type definitions in the code.
For example:
async def create_agent(
payload: AgentCreate,
):
Here:
AgentCreate
Is itself the input contract.
And:
response_model=ApiResponse
Declares:
The output must conform to the ApiResponse contract.
miniagent also enables during FastAPI initialization:
docs_url="/docs"
redoc_url="/redoc"
FastAPI generates API documentation based on OpenAPI.
OpenAPI:
OpenAPI Specification
Is a machine-readable API description standard.
This way, the API contract doesn’t just exist in people’s heads — it can be directly read by:
Frontend
Testing tools
API debugging tools
Code generators
AI
3.11 RESTful + Schema + ApiResponse Form a Complete API Standard
Using RESTful alone doesn’t solve all problems.
A truly stable API system is usually:
RESTful URL
+
HTTP Method
+
Schema
+
Status Code
+
Unified Response
+
Unified Exception
Where Schema can be understood as:
Data structure contract.
For example:
AgentCreate
AgentUpdate
AgentOut
Respectively defining:
What fields are allowed when creating an Agent
What fields are allowed when updating an Agent
What fields are included when returning an Agent
Rather than using a single:
dict
for everything.
4. What Are the Benefits?
After unifying API design, the most obvious change isn’t “prettier code” — it’s the reduction in cognitive overhead for the entire team.
4.1 APIs Become Guessable
Seeing:
GET /agents/12
Without checking documentation, you basically know:
Get Agent 12.
Seeing:
DELETE /agents/12
You can immediately tell:
Delete Agent 12.
This is:
Predictability through consistency.
4.2 Reduced Frontend-Backend Communication Cost
No need to discuss every time a new API is added:
Should it be called getAgentById or queryAgent?
The rules are already established.
4.3 Easier Test Automation
Once APIs are standardized:
POST Create
GET Query
PUT Update
DELETE Delete
Automated testing tools can more easily batch-generate tests.
4.4 More Stable Documentation
FastAPI can generate API documentation directly from:
Router
Schema
Response Model
The API definition itself is part of the documentation.
4.5 Better Suited for AI Programming
This point is especially important.
AI doesn’t need to guess:
What should the API be called?
How should the response be wrapped?
How should errors be handled?
How should pagination be designed?
It just needs to follow the rules.
5. Write API Standards Directly into AI Project Rules
Architecture design alone isn’t enough. If you want AI to comply long-term, you need to write these constraints into the project rules.
For example:
## API Design Rules
1. Follow RESTful resource-oriented API design.
2. URLs must use nouns, not CRUD verbs.
3. Use plural forms for resource names where appropriate.
4. Use GET method to read resources.
5. Use POST method to create resources.
6. Use PUT method to update resources.
7. Use PATCH method for partial state changes.
8. Use DELETE method to delete data.
9. All regular API responses must use the ApiResponse type.
10. Paginated responses must use the PageResult type.
11. Request and response data must use Pydantic schemas.
12. Routers must not return arbitrary dictionary structures.
13. Routers only handle HTTP-related concerns.
14. Business logic should be placed in Service classes.
15. Business errors must be raised as domain exceptions.
16. Do not repeat exception handling within individual routers.
17. Reuse existing API patterns before introducing new endpoints.
Simply put:
URLs only describe resources
↓
HTTP methods express actions
↓
Schema defines inputs and outputs
↓
ApiResponse unifies responses
↓
Domain exceptions are handled uniformly
↓
Routers don't contain business logic
This way, every time AI generates a new API, it already knows:
It cannot redesign a new API style.
6. How to Write Prompts That Actually Work
Don’t just tell AI:
Please help me write Agent CRUD APIs.
CRUD stands for:
Create, Read, Update, Delete
A better prompt is:
Please implement management APIs for the Agent resource.
You must follow the project's existing API contract:
- RESTful resource-oriented URLs
- Reuse the /api/v1/admin/agents path structure
- GET for querying
- POST for creating
- PUT for updating
- DELETE for deleting
- Use PATCH for partial state modifications
- Use existing Pydantic schemas for request parameters
- Use ApiResponse uniformly for return values
- Use PageResult for pagination
- Routers only handle HTTP protocol and dependency injection
- All business logic goes into AgentService
- Use the existing domain exception system for business errors
- Do not redefine exception return formats in Routers
- Before implementing, refer to existing Agent, Tool, and KnowledgeBase API styles in the project
At this point, AI’s task shifts from:
“Help me design and write an API.”
To:
“Build according to the existing contract.”
The stability of the generated code is completely different between the two.
7. Positive Outcome: The API Paradigm Already Established in miniagent
Combining the actual code from miniagent, you can see a relatively clear API chain.

In simple terms:
HTTP Request
│
▼
FastAPI Router
│
├── Path / Query
├── Pydantic Schema
├── Permission
└── HTTP Method
│
▼
Service
│
▼
Domain / Repository / Runtime
│
▼
Result
│
▼
ApiResponse
│
▼
HTTP Response
If an exception occurs during business processing:
Service
│
▼
Domain Exception
│
▼
Global Exception Handler
│
├── 400
├── 404
├── 409
└── 500
│
▼
ApiResponse
All of these parts have real implementations in miniagent:
- Routers use
GET / POST / PUT / PATCH / DELETEto describe operations. - Inputs and outputs are modeled through Pydantic Schemas.
- All regular responses uniformly use
ApiResponse. - Pagination results uniformly use
PageResult. - Business logic is moved from Routers down to Services.
- Domain exceptions are uniformly converted to HTTP status codes and response structures by the global exception handler.
- FastAPI automatically provides
/docsand/redocAPI documentation endpoints.
What ultimately emerges is not a few isolated APIs, but a set of:
Predictable, reusable, extensible API design paradigms that AI can continuously follow.
Final Thoughts
Many people first encounter RESTful and think it’s just:
GET for querying
POST for creating
PUT for updating
DELETE for deleting
But once you get into engineering practice, you realize:
The core value of RESTful is actually a unified language.
And Contract First further solves:
Fixing this language in place before code implementation begins.
For traditional development teams, this reduces communication costs. For AI programming, its value is even greater.
Because without an API contract:
AI
↓
Guesses URLs on its own
↓
Guesses HTTP methods on its own
↓
Guesses parameters on its own
↓
Guesses response structures on its own
↓
Guesses error handling on its own
↓
Project gradually develops multiple API styles
After establishing API standards:
AI
↓
Reads API Rules
↓
Follows RESTful
↓
Reuses Schema
↓
Reuses ApiResponse
↓
Calls Service
↓
Unified exception handling
AI is no longer responsible for “inventing APIs” — it only handles:
Completing implementations according to existing API contracts.
This is one of the most important ideas in architecturally constraining AI programming:
Unify the rules first, then expand generation capabilities.
When API paths, HTTP methods, inputs and outputs, status codes, and exception protocols are all stabilized, the faster AI writes, the less likely the project is to lose control.
That is the true engineering value of RESTful and Contract First.
Open Source Code
🪐 Wishing you good luck 🪐