Cursor rule
.cursor/rules/api-design.mdcCodeSpirit API 设计规范 - RESTful、路由、响应格式等
Cursor rules
Quality
54/100
Scores the file, not the repository.Length
681 words
15 headings · 9 code blocksRepository
56
— · pushed 134 days agoLast changed
3 days ago
First indexed 3 days ago.123456789# RESTful 约定1011| HTTP 方法 | 用途 | 幂等性 |12|----------|------|-------|13| **GET** | 查询资源(列表或单个) | ✅ |14| **POST** | 创建资源 | ❌ |15| **PUT** | 完整更新资源 | ✅ |16| **PATCH** | 部分更新资源 | ✅ |17| **DELETE** | 删除资源 | ✅ |1819# HTTP 状态码2021| 状态码 | 场景 | 响应方式 |22|-------|------|---------|23| 200 OK | GET/PUT/PATCH/DELETE 成功 | `SuccessResponse(data)` |24| 201 Created | POST 创建成功 | `SuccessResponseWithCreate()` |25| 400 Bad Request | 参数验证失败、业务规则错误 | `BadResponse()` 或抛出异常 |26| 401 Unauthorized | 未认证 | 框架自动处理 |27| 403 Forbidden | 无权限 | 框架自动处理 |28| 404 Not Found | 资源不存在 | 抛出 `BusinessException` |2930# 路由规范3132- 使用复数形式:`/api/users` 而非 `/api/user`33- 服务前缀:`/{service-name}/api/{controller}` (如 `/exam/api/Questions`)34- 版本控制:`/api/v{version}/{controller}` (未来需要时)3536示例:37```csharp38using CodeSpirit.Core.Attributes;39using CodeSpirit.Navigation.Resources;4041[Route("/exam/api/[controller]")]42[DisplayName("题目管理")]43[Navigation(Icon = "fa-solid fa-book",44 TitleResourceKey = "Controller.Questions",45 TitleResourceType = typeof(NavigationResources),46 PlatformType = PlatformType.Tenant)]47public class QuestionsController : ApiControllerBase48{49 [HttpGet]50 [DisplayName("获取题目列表")]51 public async Task<ActionResult<ApiResponse<PageList<QuestionDto>>>> GetList(52 [FromQuery] QuestionQueryDto query)53 {54 var result = await _service.GetPagedListAsync(query);55 return SuccessResponse(result);56 }5758 [HttpGet("{id}")]59 [DisplayName("获取题目详情")]60 public async Task<ActionResult<ApiResponse<QuestionDto>>> GetById(long id)61 {62 var result = await _service.GetByIdAsync(id);63 return SuccessResponse(result);64 }65}66```6768# Action 命名约定6970| HTTP 方法 | 方法命名 | 示例 |71|----------|---------|------|72| GET (列表) | `GetList` / `Get{Entity}s` | `GetRoles()` |73| GET (单个) | `GetById` / `Get{Entity}` | `GetRole(long id)` |74| POST | `Create` | `Create(CreateDto dto)` |75| PUT | `Update` | `Update(long id, UpdateDto dto)` |76| DELETE | `Delete` | `Delete(long id)` |77| DELETE (批量) | `BatchDelete` | `BatchDelete(long[] ids)` |7879# 响应格式8081## 基类响应方法8283```csharp84// 成功响应(带数据)- 返回 20085return SuccessResponse(data); // { status: 0, msg: "操作成功!", data: {...} }8687// 成功响应(无数据)- 返回 20088return SuccessResponse();8990// 创建成功响应 - 返回 20191return SuccessResponseWithCreate<RoleDto>(nameof(GetRole), roleDto);9293// 失败响应 - 返回指定状态码(默认 400)94return BadResponse("操作失败", code: 1, statusCode: 400);95```9697## 分页响应9899使用 `PageList<T>` 作为分页响应类型:100101```csharp102public async Task<ActionResult<ApiResponse<PageList<RoleDto>>>> GetRoles(103 [FromQuery] RoleQueryDto queryDto)104{105 PageList<RoleDto> result = await _roleService.GetRolesAsync(queryDto);106 return SuccessResponse(result);107}108```109110## 文件下载111112```csharp113// Excel 文件下载114return DownloadExcelFile(fileBytes, "导出数据.xlsx");115116// CSV 文件下载117return DownloadCsvFile(fileBytes, "导出数据.csv");118119// 通用文件下载120return DownloadFile(fileBytes, "文件名.zip", "application/zip");121122// 流式文件下载123return DownloadFile(fileStream, "大文件.pdf", "application/pdf");124```125126# 认证授权127128- 默认所有控制器需要认证(继承自基类配置)129- 匿名访问:`[AllowAnonymous]`130- 显式认证:`[Authorize]`131132```csharp133// 无需登录的控制器134[AllowAnonymous]135[Navigation(Hidden = true)]136[NoAudit("授权控制器不需要审计")]137public class AuthController : ApiControllerBase { }138139// 显式要求认证140[Authorize]141public class ApiKeysController : ApiControllerBase { }142```143144# 审计支持145146- **启用审计**:`[Audit]` - 控制器或方法级别147- **禁用审计**:`[NoAudit]` - 敏感操作或高频接口148149```csharp150// 启用审计并配置详细日志151[Audit(EntityName = nameof(Department), LogRequestParams = true, LogResponseData = true)]152public class DepartmentsController : ApiControllerBase { }153154// 禁用审计155[NoAudit("授权控制器不需要审计")]156public class AuthController : ApiControllerBase { }157```158159# 操作特性160161> 📖 详细操作特性配置参见 [controller.mdc](mdc:.cursor/rules/controller.mdc)162163操作特性用于定义前端操作按钮,必须包含:164- `DisplayName`: 操作显示名称(控制器方法)165- `Icon`: Font Awesome 图标类名166167常用操作特性:168- **Operation**: 基础操作特性169- **HeaderOperation**: 表头操作(新增、导入、导出等)170- **RowOperation**: 行操作(编辑、删除等)171- **BatchOperation**: 批量操作172173示例:174```csharp175[HttpPut("{id}/unlock")]176[Operation("解锁", "ajax", null, "确定要解除用户锁定吗?", "lockoutEnd != null",177 LabelResourceKey = "Operations.Unlock",178 LabelResourceType = typeof(OperationsResources),179 Icon = "fa-solid fa-unlock")]180[DisplayName("解锁用户")]181public async Task<ActionResult<ApiResponse>> UnlockUser(long id)182{183 await _service.UnlockAsync(id);184 return SuccessResponse();185}186```187188# 参数绑定189190| 来源 | 特性 | 示例 |191|-----|------|------|192| 查询字符串 | `[FromQuery]` | `GetList([FromQuery] QueryDto query)` |193| 请求体 | `[FromBody]` | `Create([FromBody] CreateDto dto)` |194| 路由参数 | `[FromRoute]` 或省略 | `GetById(long id)` |195| 表单数据 | `[FromForm]` | `Upload([FromForm] IFormFile file)` |196197> 💡 Action 方法如果存在多个参数,请使用 DTO 模型替代。198199# 批量操作路由200201```csharp202// 批量删除203[HttpDelete("batch")]204[DisplayName("批量删除")]205public async Task<ActionResult<ApiResponse>> BatchDelete([FromBody] long[] ids)206{207 await _service.BatchDeleteAsync(ids);208 return SuccessResponse();209}210211// 批量导入212[HttpPost("batch-import")]213[DisplayName("批量导入")]214public async Task<ActionResult<ApiResponse<BatchImportResult>>> BatchImport(215 [FromForm] IFormFile file)216{217 var result = await _service.BatchImportAsync(file);218 return SuccessResponse(result);219}220221// 导出222[HttpGet("export")]223[DisplayName("导出数据")]224public async Task<ActionResult> Export([FromQuery] ExportQueryDto query)225{226 var bytes = await _service.ExportAsync(query);227 return DownloadExcelFile(bytes, "导出数据.xlsx");228}229```230231# 异常处理232233- 不在 Action 中捕获异常234- 使用统一异常过滤器 `HttpResponseExceptionFilter`235- 抛出业务异常:`throw new BusinessException("错误消息")`236- 本地化异常:`throw new BusinessException("Errors.InvalidStartTime")`237238```csharp239// ❌ 错误:在 Action 中捕获异常240public async Task<ActionResult<ApiResponse>> Create(CreateDto dto)241{242 try243 {244 await _service.CreateAsync(dto);245 return SuccessResponse();246 }247 catch (Exception ex)248 {249 return BadResponse(ex.Message); // 不推荐250 }251}252253// ✅ 正确:让异常过滤器处理254public async Task<ActionResult<ApiResponse>> Create(CreateDto dto)255{256 await _service.CreateAsync(dto); // 异常会被过滤器捕获257 return SuccessResponse();258}259```260261# 参考文件262263- API 响应类: [ApiResponse.cs](mdc:Src/CodeSpirit.Core/ApiResponse.cs)264- 控制器基类: [ApiControllerBase.cs](mdc:Src/CodeSpirit.Shared/Controllers/ApiControllerBase.cs)265- 异常过滤器: [HttpResponseExceptionFilter.cs](mdc:Src/CodeSpirit.Shared/Filters/HttpResponseExceptionFilter.cs)266- 控制器规范: [controller.mdc](mdc:.cursor/rules/controller.mdc)267- 安全规范: [security.mdc](mdc:.cursor/rules/security.mdc)268
Also in xin-lai/CodeSpirit
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| xin-lai/CodeSpirit.cursor/rules/js.mdc · 56 | Cursor rules | apidocs | 46/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/ai-development.mdc · 56 | Cursor rules | api | 46/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/all.mdc · 56 | Cursor rules | testing-strategyapi | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/amis-cards.mdc · 56 | Cursor rules | no sections | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/controller.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/cs.mdc · 56 | Cursor rules | no sections | 25/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/csproj.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/css.mdc · 56 | Cursor rules | ui | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/database.mdc · 56 | Cursor rules | no sections | 74/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dependency-injection.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dto.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/enum.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/i18n.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/naming-conventions.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/package-management.mdc · 56 | Cursor rules | no sections | 74/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/performance.mdc · 56 | Cursor rules | no sections | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/project-structure.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/security.mdc · 56 | Cursor rules | database | 54/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/service.mdc · 56 | Cursor rules | no sections | 50/100 | 3 days ago | |
| xin-lai/CodeSpirit.cursor/rules/startup-framework.mdc · 56 | Cursor rules | api | 54/100 | 3 days ago |
Diff against .cursor/rules/js.mdc Diff against .cursor/rules/ai-development.mdc Diff against .cursor/rules/all.mdc Diff against .cursor/rules/amis-cards.mdc Diff against .cursor/rules/controller.mdc Diff against .cursor/rules/cs.mdc Diff against .cursor/rules/csproj.mdc Diff against .cursor/rules/css.mdc Diff against .cursor/rules/database.mdc Diff against .cursor/rules/dependency-injection.mdc Diff against .cursor/rules/dto.mdc Diff against .cursor/rules/enum.mdc Diff against .cursor/rules/i18n.mdc Diff against .cursor/rules/naming-conventions.mdc Diff against .cursor/rules/package-management.mdc Diff against .cursor/rules/performance.mdc Diff against .cursor/rules/project-structure.mdc Diff against .cursor/rules/security.mdc Diff against .cursor/rules/service.mdc Diff against .cursor/rules/startup-framework.mdc
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
