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

  1. 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.
  2. Change the path or HTTP method in the request body so the pair is unique.
  3. 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

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.