flipped-aurora/gin-vue-admin · warning
存在相同api
Error message
存在相同api
What it means
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.
Source
Thrown at server/service/system/sys_api.go:28
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
"gorm.io/gorm"
)
//@author: [piexlmax](https://github.com/piexlmax)
//@function: CreateApi
//@description: 新增基础api
//@param: api model.SysApi
//@return: err error
type ApiService struct{}
var ApiServiceApp = new(ApiService)
func (apiService *ApiService) CreateApi(ctx context.Context, api system.SysApi) (system.SysApi, error) {
if !errors.Is(global.GVA_DB.WithContext(ctx).Where("path = ? AND method = ?", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) {
return system.SysApi{}, errors.New("存在相同api")
}
// Create 会把自增主键回写进 api,直接返回创建后的实体(含 ID),免去调用方二次回查
err := global.GVA_DB.WithContext(ctx).Create(&api).Error
return api, err
}
func (apiService *ApiService) GetApiGroups(ctx context.Context) (groups []string, groupApiMap map[string]string, err error) {
var apis []system.SysApi
err = global.GVA_DB.WithContext(ctx).Find(&apis).Error
if err != nil {
return
}
groupApiMap = make(map[string]string, 0)
for i := range apis {
pathArr := strings.Split(apis[i].Path, "/")
newGroup := true
for i2 := range groups {
if groups[i2] == apis[i].ApiGroup {View on GitHub (pinned to 3136500ef3)
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.
Example fix
// before
gvaApi.createApi({ path: '/user/list', method: 'POST', apiGroup: 'user' })
// after: check then update
const list = await gvaApi.getApiList({ page: 1, pageSize: 100, path: '/user/list', method: 'POST' })
if (list.data.list.length > 0) {
await gvaApi.updateApi({ ...list.data.list[0], description: 'new desc' })
} else {
await gvaApi.createApi({ path: '/user/list', method: 'POST', apiGroup: 'user' })
} Defensive patterns
Strategy: validation
Validate before calling
const dup = list.some(a => a.path === form.path && a.method === form.method)
if (dup) throw new Error('相同 path+method 的 API 已存在,请直接编辑现有记录') Try / catch
try {
await createApi(form)
} catch (e) {
if (String(e?.msg).includes('存在相同api')) {
ElMessage.warning('该 path+method 已存在,请改用编辑')
} else { throw e }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/c46284b214f88fd9.
Report an issue: GitHub.