Skip to content

Backend Conventions ​

This chapter uses Spring Boot and springdoc-openapi to illustrate how backend code can produce stable OpenAPI documents, allowing API Codegen to generate readable and predictable Business APIs.

text
Spring Boot Controller / DTO
              ↓
      springdoc-openapi
              ↓
        Swagger / OpenAPI
              ↓
         API Codegen
              ↓
         Business API

Annotation syntax changes across Spring Boot and springdoc-openapi versions, but Codegen ultimately depends on paths, operationId, Tags, parameters, and response Schemas in the final OpenAPI document. Always check the actual generated document after backend changes.

Business Path Conventions ​

A Controller's first-level path should represent a stable business module:

java
@RestController
@RequestMapping("/user")
@Tag(name = "user", description = "User management")
public class UserController {
}
text
/user/list
      ↓
modulePath = user
      ↓
userApi

Use first-level paths with clear business meaning, such as /user, /order, and /role. Gateway, environment, and version prefixes should not be mixed arbitrarily into business modules. If document paths do include them, align them with Codegen's basePath and pathInDocument configuration.

Method Path Conventions ​

Paths within a module should describe stable resources or operations:

java
@GetMapping("/list")
@GetMapping("/{id}")
@PutMapping("/{id}/status")

These become the business methods' requestPath values. Once frontend code uses a path, avoid renaming it solely because of implementation refactoring.

operationId ​

Every endpoint should provide a clear, stable, and as globally unique as possible operationId through @Operation:

java
@Operation(operationId = "listUsers", summary = "List users")
@GetMapping("/list")
public AjaxResult<List<UserDto>> listUsers(UserQuery query) {
    // ...
}

operationId is the primary source of generated method names:

text
operationId: listUsers
          ↓
userApi.listUsers()

Do not rely on springdoc-openapi or an upstream generator to append numeric suffixes for duplicate names. Duplicate values trigger Codegen's duplicateMethodStrategy.

Tags ​

Use the same Tag throughout one business module and make it express the same ownership as the first-level business path:

java
@Tag(name = "user", description = "User management")
@RequestMapping("/user")

Tags affect upstream module grouping in swagger-typescript-api, while final modulePath is still derived mainly from the normalized URL path. If Tags and paths disagree, endpoints from the same module may be split or file conflicts may occur.

Parameters ​

Path Parameters ​

Path placeholders and parameter names must match, with types declared explicitly:

java
@Operation(operationId = "getUser")
@GetMapping("/{id}")
public AjaxResult<UserDto> getUser(@PathVariable("id") Long id) {
    // ...
}

OpenAPI Path parameters become separate method arguments and are inserted into the request-path template.

Query Parameters ​

Use a clear query DTO for filters, pagination, and sorting, with stable field types, names, and required status:

java
public class UserQuery {
    @Schema(description = "Name keyword")
    private String keyword;

    @Schema(description = "Page number", requiredMode = Schema.RequiredMode.REQUIRED)
    private Integer page;
}

Query parameters generated by springdoc-openapi become the frontend query object. Verify that the actual document expands the DTO into in: query parameters.

Request Body ​

Use an explicit DTO for JSON request bodies rather than accepting Object or an unconstrained Map:

java
@Operation(operationId = "createUser")
@PostMapping
public AjaxResult<UserDto> createUser(@RequestBody UserInput input) {
    // ...
}

Request Body becomes the business method's data argument. Its required status and TypeScript type come from the final Schema.

Response Models ​

Response models directly determine generated types and Business API return values:

text
Java Return Type
      ↓
OpenAPI Schema
      ↓
TypeScript Type
      ↓
Business API Return Value

Normal business endpoints should use explicit DTOs and a standard response wrapper:

java
public class AjaxResult<T> {
    private Integer code;
    private String message;
    private T data;
}

Also ensure that springdoc-openapi expands generics in the actual document. If the project generates a wrapper Schema named AjaxResultUser and configures:

ts
responseSchema: {
  namePrefix: 'AjaxResult',
  dataField: 'data',
}

Codegen tries to narrow the return type to the User corresponding to the data field. If springdoc-openapi generates unstable Schema names, declare a stable name for the concrete response:

java
@Schema(name = "AjaxResultUser")
public class UserResult extends AjaxResult<UserDto> {
}

Exact names and generic expansion depend on the project's springdoc-openapi version and configuration. Inspect the final /v3/api-docs, then align responseSchema.namePrefix with the actual Schema names.

Avoid:

  • Returning Object, raw Map, or a dynamic structure without a Schema.
  • Omitting the response body for an ordinary successful response.
  • Keeping generics only in Java types when the generated document does not expand data.
  • Declaring a Controller type that differs from the actual response structure.

When an upstream tool parses a successful response as void, the current Codegen template treats it as a download endpoint. Ordinary operations such as delete, enable, or disable should therefore declare an explicit response Schema.

Uploads and Downloads ​

Uploads ​

A Spring Boot upload endpoint should declare multipart/form-data and an explicit file field:

java
@Operation(operationId = "uploadAvatar")
@PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult<FileInfoDto> uploadAvatar(
        @RequestPart("file") MultipartFile file) {
    // ...
}

The final OpenAPI document should contain multipart/form-data, and the file field should be a binary string. Codegen does not currently switch to $http.upload() automatically. Compose or extend the generated API outside the generated directory when specialized upload behavior is required.

Downloads ​

A download endpoint should return binary content and set the media type and Content-Disposition correctly:

java
@Operation(operationId = "downloadReport")
@GetMapping(value = "/report", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> downloadReport() {
    return ResponseEntity.ok()
        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=report.csv")
        .body(resource);
}

Different OpenAPI declarations may produce different upstream parsing results. The current template generates $http.downloadFile() only when the successful response is parsed as void, so review generated download methods instead of assuming backend declarations will always trigger the conversion.

Commonly Discouraged Patterns ​

Backend patternEffect on generated output
First-level path has no stable business meaningUnstable modulePath and business API filenames
Missing or duplicate operationIdUnpredictable method names or duplicate-name conflicts
Different Tags within one moduleUpstream modules may split and cause file conflicts
Returning Object or unconstrained MapTypeScript types degrade and business return values cannot be narrowed
Successful response has no explicit SchemaIt may become void and be mistaken for a download
Path parameter names do not match placeholdersRequest template parameters are generated incorrectly
Document path contains an unconfigured gateway prefixThe wrong first-level path becomes modulePath

The acceptance criterion for backend conventions is not the annotations themselves. It is whether the final OpenAPI document expresses endpoints consistently and allows the default generation rules to produce the expected code.