mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
452 lines
11 KiB
Go
452 lines
11 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/APIParkLab/APIPark/service/service"
|
|
"github.com/APIParkLab/APIPark/service/upstream"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/APIParkLab/APIPark/service/team"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/eolinker/go-common/auto"
|
|
"github.com/eolinker/go-common/utils"
|
|
|
|
"github.com/eolinker/go-common/store"
|
|
|
|
"github.com/APIParkLab/APIPark/service/api"
|
|
|
|
api_dto "github.com/APIParkLab/APIPark/module/api/dto"
|
|
)
|
|
|
|
var _ IApiModule = (*imlApiModule)(nil)
|
|
var (
|
|
asServer = map[string]bool{
|
|
"as_server": true,
|
|
}
|
|
)
|
|
|
|
type imlApiModule struct {
|
|
teamService team.ITeamService `autowired:""`
|
|
serviceService service.IServiceService `autowired:""`
|
|
apiService api.IAPIService `autowired:""`
|
|
upstreamService upstream.IUpstreamService `autowired:""`
|
|
transaction store.ITransaction `autowired:""`
|
|
}
|
|
|
|
func (i *imlApiModule) SimpleList(ctx context.Context, serviceId string) ([]*api_dto.ApiSimpleItem, error) {
|
|
|
|
list, err := i.apiService.ListForService(ctx, serviceId)
|
|
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
|
|
return s.UUID
|
|
})...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *api_dto.ApiSimpleItem {
|
|
return &api_dto.ApiSimpleItem{
|
|
Id: item.UUID,
|
|
Name: item.Name,
|
|
Method: item.Method,
|
|
Path: item.Path,
|
|
}
|
|
})
|
|
return out, nil
|
|
}
|
|
|
|
func (i *imlApiModule) Detail(ctx context.Context, serviceId string, apiId string) (*api_dto.ApiDetail, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
detail, err := i.apiService.GetInfo(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
apiDetail := &api_dto.ApiDetail{
|
|
ApiSimpleDetail: *api_dto.GenApiSimpleDetail(detail),
|
|
}
|
|
proxy, err := i.apiService.LatestProxy(ctx, apiId)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
}
|
|
if proxy != nil {
|
|
|
|
apiDetail.Proxy = api_dto.FromServiceProxy(proxy.Data)
|
|
}
|
|
|
|
document, err := i.apiService.LatestDocument(ctx, apiId)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
}
|
|
if document != nil {
|
|
doc := make(map[string]interface{})
|
|
err = json.Unmarshal([]byte(document.Data.Content), &doc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiDetail.Doc = doc
|
|
}
|
|
|
|
return apiDetail, nil
|
|
}
|
|
|
|
func (i *imlApiModule) SimpleDetail(ctx context.Context, serviceId string, apiId string) (*api_dto.ApiSimpleDetail, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
detail, err := i.apiService.GetInfo(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return api_dto.GenApiSimpleDetail(detail), nil
|
|
}
|
|
|
|
func (i *imlApiModule) Search(ctx context.Context, keyword string, serviceId string) ([]*api_dto.ApiItem, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
list, err := i.apiService.Search(ctx, keyword, map[string]interface{}{
|
|
"service": serviceId,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
|
|
return s.UUID
|
|
})...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
utils.Sort(apiInfos, func(a, b *api.Info) bool {
|
|
return a.UpdateAt.After(b.UpdateAt)
|
|
})
|
|
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *api_dto.ApiItem {
|
|
return &api_dto.ApiItem{
|
|
Id: item.UUID,
|
|
Name: item.Name,
|
|
Method: item.Method,
|
|
Path: item.Path,
|
|
Creator: auto.UUID(item.Creator),
|
|
Updater: auto.UUID(item.Updater),
|
|
CreateTime: auto.TimeLabel(item.CreateAt),
|
|
UpdateTime: auto.TimeLabel(item.UpdateAt),
|
|
CanDelete: true,
|
|
}
|
|
})
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (i *imlApiModule) SimpleSearch(ctx context.Context, keyword string, serviceId string) ([]*api_dto.ApiSimpleItem, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
list, err := i.apiService.Search(ctx, keyword, map[string]interface{}{
|
|
"service": serviceId,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
|
|
return s.UUID
|
|
})...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *api_dto.ApiSimpleItem {
|
|
return &api_dto.ApiSimpleItem{
|
|
Id: item.UUID,
|
|
Name: item.Name,
|
|
Method: item.Method,
|
|
Path: item.Path,
|
|
}
|
|
})
|
|
return out, nil
|
|
}
|
|
|
|
func (i *imlApiModule) Create(ctx context.Context, serviceId string, dto *api_dto.CreateApi) (*api_dto.ApiSimpleDetail, error) {
|
|
info, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
prefix, err := i.Prefix(ctx, serviceId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
if dto.Id == "" {
|
|
dto.Id = uuid.New().String()
|
|
}
|
|
err = dto.Validate()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
path := fmt.Sprintf("%s%s", prefix, dto.Path)
|
|
err = i.apiService.Exist(ctx, "", &api.ExistAPI{Path: dto.Path, Method: dto.Method})
|
|
if err != nil {
|
|
return fmt.Errorf("api path %s,method: %s already exist", dto.Path, dto.Method)
|
|
}
|
|
proxy := api_dto.ToServiceProxy(dto.Proxy)
|
|
err = i.apiService.SaveProxy(ctx, dto.Id, proxy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = i.apiService.SaveDocument(ctx, dto.Id, api_dto.ToServiceDocument(nil))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
match, _ := json.Marshal(dto.MatchRules)
|
|
return i.apiService.Create(ctx, &api.CreateAPI{
|
|
UUID: dto.Id,
|
|
Name: dto.Name,
|
|
Description: dto.Description,
|
|
Service: serviceId,
|
|
Team: info.Team,
|
|
Method: dto.Method,
|
|
Path: path,
|
|
Match: string(match),
|
|
//Upstream: proxy.Upstream,
|
|
})
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return i.SimpleDetail(ctx, serviceId, dto.Id)
|
|
}
|
|
|
|
func (i *imlApiModule) Edit(ctx context.Context, serviceId string, apiId string, dto *api_dto.EditApi) (*api_dto.ApiSimpleDetail, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
var up *string
|
|
if dto.Proxy != nil {
|
|
err = i.apiService.SaveProxy(ctx, apiId, api_dto.ToServiceProxy(dto.Proxy))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//if dto.Proxy.Upstream != "" {
|
|
// up = &dto.Proxy.Upstream
|
|
//}
|
|
}
|
|
err = i.apiService.Save(ctx, apiId, &api.EditAPI{
|
|
Name: dto.Info.Name,
|
|
Description: dto.Info.Description,
|
|
Upstream: up,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if dto.Doc != nil {
|
|
err = i.apiService.SaveDocument(ctx, apiId, api_dto.ToServiceDocument(*dto.Doc))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return i.SimpleDetail(ctx, serviceId, apiId)
|
|
}
|
|
|
|
func (i *imlApiModule) Delete(ctx context.Context, serviceId string, apiId string) error {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return i.apiService.Delete(ctx, apiId)
|
|
}
|
|
|
|
func (i *imlApiModule) Copy(ctx context.Context, serviceId string, apiId string, dto *api_dto.CreateApi) (*api_dto.ApiSimpleDetail, error) {
|
|
info, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
oldApi, err := i.apiService.Get(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
prefix, err := i.Prefix(ctx, serviceId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
if dto.Id == "" {
|
|
dto.Id = uuid.New().String()
|
|
}
|
|
err = dto.Validate()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
path := fmt.Sprintf("%s/%s", strings.TrimSuffix(prefix, "/"), strings.TrimPrefix(dto.Path, "/"))
|
|
err = i.apiService.Exist(ctx, serviceId, &api.ExistAPI{Path: path, Method: dto.Method})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
proxy, err := i.apiService.LatestProxy(ctx, oldApi.UUID)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
}
|
|
//upstreamId := ""
|
|
if proxy != nil {
|
|
err = i.apiService.SaveProxy(ctx, dto.Id, proxy.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//upstreamId = proxy.Data.Upstream
|
|
}
|
|
|
|
doc, err := i.apiService.LatestDocument(ctx, oldApi.UUID)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
}
|
|
if doc != nil {
|
|
err = i.apiService.SaveDocument(ctx, dto.Id, doc.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
match, _ := json.Marshal(dto.MatchRules)
|
|
return i.apiService.Create(ctx, &api.CreateAPI{
|
|
UUID: dto.Id,
|
|
Name: dto.Name,
|
|
Service: serviceId,
|
|
Team: info.Team,
|
|
Method: dto.Method,
|
|
Path: path,
|
|
Match: string(match),
|
|
//Upstream: upstreamId,
|
|
})
|
|
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return i.SimpleDetail(ctx, serviceId, dto.Id)
|
|
}
|
|
|
|
func (i *imlApiModule) ApiDocDetail(ctx context.Context, serviceId string, apiId string) (*api_dto.ApiDocDetail, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
apiBase, err := i.apiService.Get(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if apiBase.IsDelete {
|
|
return nil, errors.New("api is delete")
|
|
}
|
|
|
|
detail, err := i.apiService.GetInfo(ctx, apiBase.UUID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
document, err := i.apiService.LatestDocument(ctx, apiId)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
}
|
|
var doc map[string]interface{}
|
|
if document != nil {
|
|
doc = make(map[string]interface{})
|
|
err = json.Unmarshal([]byte(document.Data.Content), &doc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &api_dto.ApiDocDetail{
|
|
ApiSimpleDetail: *api_dto.GenApiSimpleDetail(detail),
|
|
Doc: doc,
|
|
}, nil
|
|
}
|
|
|
|
func (i *imlApiModule) ApiProxyDetail(ctx context.Context, serviceId string, apiId string) (*api_dto.ApiProxyDetail, error) {
|
|
_, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiBase, err := i.apiService.Get(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if apiBase.IsDelete {
|
|
return nil, errors.New("api is delete")
|
|
}
|
|
if apiBase.Service != serviceId {
|
|
return nil, errors.New("api is not in project")
|
|
}
|
|
|
|
detail, err := i.apiService.GetInfo(ctx, apiId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
apiDetail := &api_dto.ApiProxyDetail{
|
|
ApiSimpleDetail: *api_dto.GenApiSimpleDetail(detail),
|
|
}
|
|
proxy, err := i.apiService.LatestProxy(ctx, apiId)
|
|
if err != nil {
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
}
|
|
if proxy != nil {
|
|
apiDetail.Proxy = api_dto.FromServiceProxy(proxy.Data)
|
|
}
|
|
return apiDetail, nil
|
|
|
|
}
|
|
|
|
func (i *imlApiModule) Prefix(ctx context.Context, serviceId string) (string, error) {
|
|
pInfo, err := i.serviceService.Check(ctx, serviceId, asServer)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if pInfo.Prefix != "" {
|
|
if pInfo.Prefix[0] != '/' {
|
|
pInfo.Prefix = fmt.Sprintf("/%s", strings.TrimSuffix(pInfo.Prefix, "/"))
|
|
}
|
|
}
|
|
return strings.TrimSuffix(pInfo.Prefix, "/"), nil
|
|
}
|