{"record":{"id":"c46284b214f88fd9","repo":"flipped-aurora/gin-vue-admin","slug":"api-c46284","errorCode":null,"errorMessage":"存在相同api","messagePattern":"存在相同api","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/service/system/sys_api.go","lineNumber":28,"sourceCode":"\t\"github.com/flipped-aurora/gin-vue-admin/server/model/common/request\"\n\t\"github.com/flipped-aurora/gin-vue-admin/server/model/system\"\n\tsystemRes \"github.com/flipped-aurora/gin-vue-admin/server/model/system/response\"\n\t\"gorm.io/gorm\"\n)\n\n//@author: [piexlmax](https://github.com/piexlmax)\n//@function: CreateApi\n//@description: 新增基础api\n//@param: api model.SysApi\n//@return: err error\n\ntype ApiService struct{}\n\nvar ApiServiceApp = new(ApiService)\n\nfunc (apiService *ApiService) CreateApi(ctx context.Context, api system.SysApi) (system.SysApi, error) {\n\tif !errors.Is(global.GVA_DB.WithContext(ctx).Where(\"path = ? AND method = ?\", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) {\n\t\treturn system.SysApi{}, errors.New(\"存在相同api\")\n\t}\n\t// Create 会把自增主键回写进 api,直接返回创建后的实体(含 ID),免去调用方二次回查\n\terr := global.GVA_DB.WithContext(ctx).Create(&api).Error\n\treturn api, err\n}\n\nfunc (apiService *ApiService) GetApiGroups(ctx context.Context) (groups []string, groupApiMap map[string]string, err error) {\n\tvar apis []system.SysApi\n\terr = global.GVA_DB.WithContext(ctx).Find(&apis).Error\n\tif err != nil {\n\t\treturn\n\t}\n\tgroupApiMap = make(map[string]string, 0)\n\tfor i := range apis {\n\t\tpathArr := strings.Split(apis[i].Path, \"/\")\n\t\tnewGroup := true\n\t\tfor i2 := range groups {\n\t\t\tif groups[i2] == apis[i].ApiGroup {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_api.go#L10-L46","documentation":"CreateApi rejects creating a system API entry whose path+method pair already exists. Before inserting, it runs a First() query on sys_api filtered by path and method; if any row is found (i.e. the error is NOT gorm.ErrRecordNotFound), it returns \"存在相同api\" instead of creating a duplicate. This enforces uniqueness of the (path, method) composite key at the service layer.","triggerScenarios":"Calling POST /api/api (api.CreateApi) with a body whose {path, method} matches an existing row in the sys_api table. Also occurs when re-submitting a form after a partial success, or when importing API seeds (server/source/system/api.go) that are already registered in the DB.","commonSituations":"Initializing a fresh environment where the casbin/api seed data was inserted twice; a developer adds an endpoint to the API management page that the auto-registration or migration already created; copying an existing API row and changing only the description while leaving path/method untouched.","solutions":["Query the existing record first (GET /api/getApiList or getApiById filtered by path+method) and update it via UpdateApi instead of creating a new one.","Change the path or HTTP method in the request body so the pair is unique.","If the old entry is stale, delete it via DELETE /api/deleteApi then retry CreateApi."],"exampleFix":"// before\ngvaApi.createApi({ path: '/user/list', method: 'POST', apiGroup: 'user' })\n\n// after: check then update\nconst list = await gvaApi.getApiList({ page: 1, pageSize: 100, path: '/user/list', method: 'POST' })\nif (list.data.list.length > 0) {\n  await gvaApi.updateApi({ ...list.data.list[0], description: 'new desc' })\n} else {\n  await gvaApi.createApi({ path: '/user/list', method: 'POST', apiGroup: 'user' })\n}","handlingStrategy":"validation","validationCode":"const dup = list.some(a => a.path === form.path && a.method === form.method)\nif (dup) throw new Error('相同 path+method 的 API 已存在，请直接编辑现有记录')","typeGuard":null,"tryCatchPattern":"try {\n  await createApi(form)\n} catch (e) {\n  if (String(e?.msg).includes('存在相同api')) {\n    ElMessage.warning('该 path+method 已存在，请改用编辑')\n  } else { throw e }\n}","preventionTips":["Before creating, search the API management page for the exact path and method.","Treat (path, method) as a composite unique key in all import/seed scripts.","Make create flows idempotent: check-then-update instead of blind create.","After seeding/migrations, diff the sys_api table against your source-of-truth list."],"tags":["duplicate-record","api-management","gorm","validation"],"backgroundTag":"duplicate-unique-key","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}