Skip to content

Commit c3fe261

Browse files
authored
Merge pull request #946 from dushaniw/main
add changes for Refactoring Deployment API Endpoints for Better RESTful design
2 parents f93f364 + cbaaba3 commit c3fe261

File tree

5 files changed

+169
-79
lines changed

5 files changed

+169
-79
lines changed

platform-api/src/internal/constants/error.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,18 @@ var (
6565
)
6666

6767
var (
68-
ErrDeploymentNotFound = errors.New("deployment not found")
69-
ErrDeploymentNotActive = errors.New("no active deployment found for this API on the gateway")
70-
ErrDeploymentIsDeployed = errors.New("cannot delete an active deployment - undeploy it first")
71-
ErrDeploymentAlreadyActive = errors.New("deployment is already active")
72-
ErrBaseDeploymentNotFound = errors.New("base deployment not found")
73-
ErrInvalidDeploymentStatus = errors.New("invalid deployment status")
74-
ErrDeploymentNameRequired = errors.New("deployment name is required")
75-
ErrDeploymentBaseRequired = errors.New("base is required")
76-
ErrDeploymentGatewayIDRequired = errors.New("gatewayId is required")
77-
ErrAPINoBackendServices = errors.New("API must have at least one backend service attached before deployment")
78-
ErrDeploymentAlreadyDeployed = errors.New("cannot rollback to currently deployed deployment")
68+
ErrDeploymentNotFound = errors.New("deployment not found")
69+
ErrDeploymentNotActive = errors.New("no active deployment found for this API on the gateway")
70+
ErrDeploymentIsDeployed = errors.New("cannot delete an active deployment - undeploy it first")
71+
ErrDeploymentAlreadyActive = errors.New("deployment is already active")
72+
ErrBaseDeploymentNotFound = errors.New("base deployment not found")
73+
ErrInvalidDeploymentStatus = errors.New("invalid deployment status")
74+
ErrDeploymentNameRequired = errors.New("deployment name is required")
75+
ErrDeploymentBaseRequired = errors.New("base is required")
76+
ErrDeploymentGatewayIDRequired = errors.New("gatewayId is required")
77+
ErrAPINoBackendServices = errors.New("API must have at least one backend service attached before deployment")
78+
ErrDeploymentAlreadyDeployed = errors.New("cannot restore to the currently deployed deployment")
79+
ErrGatewayIDMismatch = errors.New("gateway ID mismatch: deployment is bound to a different gateway")
7980
)
8081

8182
var (

platform-api/src/internal/handler/deployment.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (h *DeploymentHandler) DeployAPI(c *gin.Context) {
127127
c.JSON(http.StatusCreated, deployment)
128128
}
129129

130-
// UndeployDeployment handles POST /api/v1/apis/:apiId/deployments/:deploymentId/undeploy
130+
// UndeployDeployment handles POST /api/v1/apis/:apiId/deployments/undeploy
131131
// Undeploys an active deployment by changing its status to UNDEPLOYED
132132
func (h *DeploymentHandler) UndeployDeployment(c *gin.Context) {
133133
orgId, exists := middleware.GetOrganizationFromContext(c)
@@ -138,7 +138,8 @@ func (h *DeploymentHandler) UndeployDeployment(c *gin.Context) {
138138
}
139139

140140
apiId := c.Param("apiId")
141-
deploymentId := c.Param("deploymentId")
141+
deploymentId := c.Query("deploymentId")
142+
gatewayId := c.Query("gatewayId")
142143

143144
if apiId == "" {
144145
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
@@ -147,11 +148,16 @@ func (h *DeploymentHandler) UndeployDeployment(c *gin.Context) {
147148
}
148149
if deploymentId == "" {
149150
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
150-
"Deployment ID is required"))
151+
"deploymentId query parameter is required"))
152+
return
153+
}
154+
if gatewayId == "" {
155+
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
156+
"gatewayId query parameter is required"))
151157
return
152158
}
153159

154-
deployment, err := h.deploymentService.UndeployDeploymentByHandle(apiId, deploymentId, orgId)
160+
deployment, err := h.deploymentService.UndeployDeploymentByHandle(apiId, deploymentId, gatewayId, orgId)
155161
if err != nil {
156162
if errors.Is(err, constants.ErrAPINotFound) {
157163
c.JSON(http.StatusNotFound, utils.NewErrorResponse(404, "Not Found",
@@ -173,17 +179,22 @@ func (h *DeploymentHandler) UndeployDeployment(c *gin.Context) {
173179
"No active deployment found for this API on the gateway"))
174180
return
175181
}
176-
log.Printf("[ERROR] Failed to undeploy: apiId=%s deploymentId=%s error=%v", apiId, deploymentId, err)
182+
if errors.Is(err, constants.ErrGatewayIDMismatch) {
183+
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
184+
"Deployment is bound to a different gateway"))
185+
return
186+
}
187+
log.Printf("[ERROR] Failed to undeploy: apiId=%s deploymentId=%s gatewayId=%s error=%v", apiId, deploymentId, gatewayId, err)
177188
c.JSON(http.StatusInternalServerError, utils.NewErrorResponse(500, "Internal Server Error", "Failed to undeploy deployment"))
178189
return
179190
}
180191

181192
c.JSON(http.StatusOK, deployment)
182193
}
183194

184-
// RollbackDeployment handles POST /api/v1/apis/:apiId/rollback-deployment
185-
// Rolls back to a previous deployment (ARCHIVED or UNDEPLOYED)
186-
func (h *DeploymentHandler) RollbackDeployment(c *gin.Context) {
195+
// RestoreDeployment handles POST /api/v1/apis/:apiId/deployments/restore
196+
// Restores a previous deployment (ARCHIVED or UNDEPLOYED)
197+
func (h *DeploymentHandler) RestoreDeployment(c *gin.Context) {
187198
orgId, exists := middleware.GetOrganizationFromContext(c)
188199
if !exists {
189200
c.JSON(http.StatusUnauthorized, utils.NewErrorResponse(401, "Unauthorized",
@@ -193,6 +204,7 @@ func (h *DeploymentHandler) RollbackDeployment(c *gin.Context) {
193204

194205
apiId := c.Param("apiId")
195206
deploymentId := c.Query("deploymentId")
207+
gatewayId := c.Query("gatewayId")
196208

197209
if apiId == "" {
198210
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
@@ -204,8 +216,13 @@ func (h *DeploymentHandler) RollbackDeployment(c *gin.Context) {
204216
"deploymentId query parameter is required"))
205217
return
206218
}
219+
if gatewayId == "" {
220+
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
221+
"gatewayId query parameter is required"))
222+
return
223+
}
207224

208-
deployment, err := h.deploymentService.RollbackDeploymentByHandle(apiId, deploymentId, orgId)
225+
deployment, err := h.deploymentService.RestoreDeploymentByHandle(apiId, deploymentId, gatewayId, orgId)
209226
if err != nil {
210227
if errors.Is(err, constants.ErrAPINotFound) {
211228
c.JSON(http.StatusNotFound, utils.NewErrorResponse(404, "Not Found",
@@ -224,11 +241,16 @@ func (h *DeploymentHandler) RollbackDeployment(c *gin.Context) {
224241
}
225242
if errors.Is(err, constants.ErrDeploymentAlreadyDeployed) {
226243
c.JSON(http.StatusConflict, utils.NewErrorResponse(409, "Conflict",
227-
"Cannot rollback to currently deployed deployment"))
244+
"Cannot restore currently deployed deployment"))
245+
return
246+
}
247+
if errors.Is(err, constants.ErrGatewayIDMismatch) {
248+
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request",
249+
"Deployment is bound to a different gateway"))
228250
return
229251
}
230-
log.Printf("[ERROR] Failed to rollback deployment: apiId=%s deploymentId=%s error=%v", apiId, deploymentId, err)
231-
c.JSON(http.StatusInternalServerError, utils.NewErrorResponse(500, "Internal Server Error", "Failed to rollback deployment"))
252+
log.Printf("[ERROR] Failed to restore deployment: apiId=%s deploymentId=%s gatewayId=%s error=%v", apiId, deploymentId, gatewayId, err)
253+
c.JSON(http.StatusInternalServerError, utils.NewErrorResponse(500, "Internal Server Error", "Failed to restore deployment"))
232254
return
233255
}
234256

@@ -375,11 +397,11 @@ func (h *DeploymentHandler) GetDeployments(c *gin.Context) {
375397
func (h *DeploymentHandler) RegisterRoutes(r *gin.Engine) {
376398
apiGroup := r.Group("/api/v1/apis/:apiId")
377399
{
378-
apiGroup.POST("/deploy", h.DeployAPI)
379-
apiGroup.POST("/rollback-deployment", h.RollbackDeployment)
400+
apiGroup.POST("/deployments", h.DeployAPI)
401+
apiGroup.POST("/deployments/undeploy", h.UndeployDeployment)
402+
apiGroup.POST("/deployments/restore", h.RestoreDeployment)
380403
apiGroup.GET("/deployments", h.GetDeployments)
381404
apiGroup.GET("/deployments/:deploymentId", h.GetDeployment)
382-
apiGroup.POST("/deployments/:deploymentId/undeploy", h.UndeployDeployment)
383405
apiGroup.DELETE("/deployments/:deploymentId", h.DeleteDeployment)
384406
}
385407
}

platform-api/src/internal/service/deployment.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ func (s *DeploymentService) DeployAPI(apiUUID string, req *dto.DeployAPIRequest,
223223
}, nil
224224
}
225225

226-
// RollbackDeployment rolls back to a previous deployment (can be ARCHIVED or UNDEPLOYED)
227-
func (s *DeploymentService) RollbackDeployment(apiUUID, deploymentID, orgUUID string) (*dto.DeploymentResponse, error) {
226+
// RestoreDeployment restores a previous deployment (can be ARCHIVED or UNDEPLOYED)
227+
func (s *DeploymentService) RestoreDeployment(apiUUID, deploymentID, gatewayID, orgUUID string) (*dto.DeploymentResponse, error) {
228228
// Verify target deployment exists and belongs to the API
229229
targetDeployment, err := s.apiRepo.GetDeploymentWithContent(deploymentID, apiUUID, orgUUID)
230230
if err != nil {
@@ -234,6 +234,11 @@ func (s *DeploymentService) RollbackDeployment(apiUUID, deploymentID, orgUUID st
234234
return nil, constants.ErrDeploymentNotFound
235235
}
236236

237+
// Validate that the provided gatewayID matches the deployment's bound gateway
238+
if targetDeployment.GatewayID != gatewayID {
239+
return nil, constants.ErrGatewayIDMismatch
240+
}
241+
237242
// Verify target deployment is NOT currently DEPLOYED
238243
currentDeploymentID, status, _, err := s.apiRepo.GetDeploymentStatus(apiUUID, orgUUID, targetDeployment.GatewayID)
239244
if err != nil {
@@ -286,7 +291,7 @@ func (s *DeploymentService) RollbackDeployment(apiUUID, deploymentID, orgUUID st
286291
}
287292

288293
// UndeployDeployment undeploys an active deployment
289-
func (s *DeploymentService) UndeployDeployment(apiUUID, deploymentID, orgUUID string) (*dto.DeploymentResponse, error) {
294+
func (s *DeploymentService) UndeployDeployment(apiUUID, deploymentID, gatewayID, orgUUID string) (*dto.DeploymentResponse, error) {
290295
// Verify deployment exists and belongs to API
291296
deployment, err := s.apiRepo.GetDeploymentWithState(deploymentID, apiUUID, orgUUID)
292297
if err != nil {
@@ -296,6 +301,11 @@ func (s *DeploymentService) UndeployDeployment(apiUUID, deploymentID, orgUUID st
296301
return nil, constants.ErrDeploymentNotFound
297302
}
298303

304+
// Validate that the provided gatewayID matches the deployment's bound gateway
305+
if deployment.GatewayID != gatewayID {
306+
return nil, constants.ErrGatewayIDMismatch
307+
}
308+
299309
// Verify deployment is currently DEPLOYED (status already populated by GetDeploymentWithState)
300310
if deployment.Status == nil || *deployment.Status != model.DeploymentStatusDeployed {
301311
return nil, constants.ErrDeploymentNotActive
@@ -562,15 +572,15 @@ func (s *DeploymentService) DeployAPIByHandle(apiHandle string, req *dto.DeployA
562572
return s.DeployAPI(apiUUID, req, orgUUID)
563573
}
564574

565-
// RollbackDeploymentByHandle rolls back to a previous deployment using API handle
566-
func (s *DeploymentService) RollbackDeploymentByHandle(apiHandle, deploymentID, orgUUID string) (*dto.DeploymentResponse, error) {
575+
// RestoreDeploymentByHandle restores a previous deployment using API handle
576+
func (s *DeploymentService) RestoreDeploymentByHandle(apiHandle, deploymentID, gatewayID, orgUUID string) (*dto.DeploymentResponse, error) {
567577
// Convert API handle to UUID
568578
apiUUID, err := s.getAPIUUIDByHandle(apiHandle, orgUUID)
569579
if err != nil {
570580
return nil, err
571581
}
572582

573-
return s.RollbackDeployment(apiUUID, deploymentID, orgUUID)
583+
return s.RestoreDeployment(apiUUID, deploymentID, gatewayID, orgUUID)
574584
}
575585

576586
// getAPIUUIDByHandle retrieves the internal UUID for an API by its handle
@@ -623,14 +633,14 @@ func (s *DeploymentService) GetDeploymentsByHandle(apiHandle, gatewayID, status,
623633
}
624634

625635
// UndeployDeploymentByHandle undeploys a deployment using API handle
626-
func (s *DeploymentService) UndeployDeploymentByHandle(apiHandle, deploymentID, orgUUID string) (*dto.DeploymentResponse, error) {
636+
func (s *DeploymentService) UndeployDeploymentByHandle(apiHandle, deploymentID, gatewayID, orgUUID string) (*dto.DeploymentResponse, error) {
627637
// Convert API handle to UUID
628638
apiUUID, err := s.getAPIUUIDByHandle(apiHandle, orgUUID)
629639
if err != nil {
630640
return nil, err
631641
}
632642

633-
return s.UndeployDeployment(apiUUID, deploymentID, orgUUID)
643+
return s.UndeployDeployment(apiUUID, deploymentID, gatewayID, orgUUID)
634644
}
635645

636646
// DeleteDeploymentByHandle deletes a deployment using API handle

0 commit comments

Comments
 (0)