Skip to content

Commit

Permalink
[TT-7387] Delete API version atomically in OSS (TykTechnologies#4586)
Browse files Browse the repository at this point in the history
  • Loading branch information
furkansenharputlu authored Dec 28, 2022
1 parent c39290e commit bdfa216
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
35 changes: 34 additions & 1 deletion gateway/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,39 @@ func (gw *Gateway) handleDeleteAPI(apiID string) (interface{}, int) {
os.Remove(defOASFilePath)
}

if spec.VersionDefinition.BaseID != "" {
baseAPIPtr := gw.getApiSpec(spec.VersionDefinition.BaseID)
apiInBytes, err := json.Marshal(baseAPIPtr)
if err != nil {
log.WithError(err).Error("Couldn't marshal API spec")
}

var baseAPI APISpec
err = json.Unmarshal(apiInBytes, &baseAPI)
if err != nil {
log.WithError(err).Error("Couldn't unmarshal API spec")
}

for versionName, versionAPIID := range baseAPI.VersionDefinition.Versions {
if apiID == versionAPIID {
delete(baseAPI.VersionDefinition.Versions, versionName)
if baseAPI.VersionDefinition.Default == versionName {
baseAPI.VersionDefinition.Default = baseAPI.VersionDefinition.Name
}

break
}
}

fs := afero.NewOsFs()
if !baseAPI.IsOAS {
err, _ := gw.writeToFile(fs, baseAPI.APIDefinition, baseAPI.APIID)
if err != nil {
log.WithError(err).Errorf("Error occurred while updating base API with id: %s", baseAPI.APIID)
}
}
}

response := apiModifyKeySuccess{
Key: apiID,
Status: "ok",
Expand Down Expand Up @@ -1363,7 +1396,7 @@ func (gw *Gateway) apiHandler(w http.ResponseWriter, r *http.Request) {
} else {
obj, code = apiError("Must specify an apiID to update"), http.StatusBadRequest
}
case "DELETE":
case http.MethodDelete:
if apiID != "" {
log.Debug("Deleting API definition for: ", apiID)
obj, code = gw.handleDeleteAPI(apiID)
Expand Down
61 changes: 61 additions & 0 deletions gateway/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2180,6 +2180,67 @@ func TestHandleAddOASApi_AddVersionAtomically(t *testing.T) {
_, _ = ts.Run(t, test.TestCase{AdminAuth: true, Path: "/tyk/apis/oas/" + v2APIID, HeadersMatch: baseAPIHeader(baseAPI.APIID), Code: http.StatusOK})
}

func TestHandleDeleteAPI_RemoveVersionAtomically(t *testing.T) {
ts := StartTest(nil)
defer ts.Close()

const (
v1VersionName = "v1-version-name"
v2VersionName = "v2-version-name"
)

v1 := BuildAPI(func(a *APISpec) {
a.APIID = "v1"
})[0]
v2 := BuildAPI(func(a *APISpec) {
a.APIID = "v2"
})[0]
baseAPI := BuildAPI(func(a *APISpec) {
a.APIID = "base"
a.VersionDefinition.Versions = map[string]string{
v1VersionName: v1.APIID,
v2VersionName: v2.APIID,
}
a.VersionDefinition.Default = v1VersionName
a.VersionDefinition.Name = v2VersionName
})[0]

_, _ = ts.Run(t, []test.TestCase{
{AdminAuth: true, Method: http.MethodPost, Path: "/tyk/apis", Data: v1, Code: http.StatusOK},
{AdminAuth: true, Method: http.MethodPost, Path: "/tyk/apis", Data: v2, Code: http.StatusOK},
{AdminAuth: true, Method: http.MethodPost, Path: "/tyk/apis", Data: baseAPI, Code: http.StatusOK},
}...)

ts.Gw.DoReload()

_, _ = ts.Run(t, []test.TestCase{
{AdminAuth: true, Path: "/tyk/apis/" + v1.APIID, HeadersMatch: baseAPIHeader(baseAPI.APIID), Code: http.StatusOK},
{AdminAuth: true, Path: "/tyk/apis/" + v2.APIID, HeadersMatch: baseAPIHeader(baseAPI.APIID), Code: http.StatusOK},
{AdminAuth: true, Method: http.MethodDelete, Path: "/tyk/apis/" + v1.APIID, Code: http.StatusOK},
}...)

ts.Gw.DoReload()

_, _ = ts.Run(t, []test.TestCase{
{AdminAuth: true, Path: "/tyk/apis/" + v1.APIID, BodyMatch: "API not found", Code: http.StatusNotFound},
{AdminAuth: true, Path: "/tyk/apis/" + v2.APIID, HeadersMatch: baseAPIHeader(baseAPI.APIID), Code: http.StatusOK},
{AdminAuth: true, Path: "/tyk/apis/" + baseAPI.APIID, BodyMatchFunc: func(bytes []byte) bool {
var base apidef.APIDefinition
err := json.Unmarshal(bytes, &base)
assert.NoError(t, err)

expectedVersions := map[string]string{
v2VersionName: v2.APIID,
}

assert.Equal(t, expectedVersions, base.VersionDefinition.Versions)
assert.Equal(t, v2VersionName, base.VersionDefinition.Default)

return true
}, Code: http.StatusOK},
}...)
}

func baseAPIHeader(id string) map[string]string {
return map[string]string{
apidef.HeaderBaseAPIID: id,
Expand Down

0 comments on commit bdfa216

Please sign in to comment.