Skip to content

Commit 6702374

Browse files
committed
Get gateways that a API is deployed
1 parent 8b8653f commit 6702374

File tree

6 files changed

+157
-6
lines changed

6 files changed

+157
-6
lines changed

platform-api/spec/impls/api-lifecycle-management.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
## Entry Points
44

5-
- `platform-api/src/internal/handler/api.go` – implements `/api/v1/apis` CRUD, `/api/v1/projects/:projectId/apis` listing routes and `/api/v1/apis/:apiId/deploy-revision` for API deployment
6-
- `platform-api/src/internal/service/api.go` – validates names, contexts, versions, orchestrates default values and generates deployment YAML and deploys APIs in the Gateway plus repository calls.
5+
- `platform-api/src/internal/handler/api.go` – implements `/api/v1/apis` CRUD, `/api/v1/projects/:projectId/apis` listing routes, `/api/v1/apis/:apiId/deploy-revision` for API deployment, and `/api/v1/apis/:apiId/gateways` for retrieving deployment status
6+
- `platform-api/src/internal/service/api.go` – validates names, contexts, versions, orchestrates default values and generates deployment YAML and deploys APIs in the Gateway plus repository calls. Also handles gateway deployment queries.
77
- `platform-api/src/internal/repository/api.go` – persists APIs, security, CORS, backend services, rate limiting, and operations using transactions.
8-
- `platform-api/src/internal/database/schema.sql` – contains tables for APIs, security configs, backend services, rate limits, and operations.
8+
- `platform-api/src/internal/repository/gateway.go` – handles gateway operations including querying which gateways have specific APIs deployed.
9+
- `platform-api/src/internal/database/schema.sql` – contains tables for APIs, security configs, backend services, rate limits, operations, and API deployments tracking.
910
- `platform-api/src/resources/openapi.yaml` – provides the published API lifecycle contract for client integrations.
1011

1112
## Behaviour
@@ -14,10 +15,15 @@
1415
2. Repository layer writes the main API record and related configuration tables within a single transaction.
1516
3. GET routes return fully hydrated API structures, including nested security and backend definitions.
1617
4. Update requests replace mutable fields and rebuild related configuration sets; deletes cascade via foreign keys.
17-
5. Generates comprehensive deployment API YAML including:
18+
5. Gateway deployment tracking uses the `api_deployments` table to maintain relationships between APIs and gateways.
19+
6. The gateways endpoint queries deployed APIs by joining API deployments with gateway records, filtered by organization for security.
20+
7. Generates comprehensive deployment API YAML including:
1821
- API metadata and configuration
1922
- Security policies (mTLS, OAuth2, API Key)
23+
24+
## Verification
2025
- Create: `curl -k -X POST https://localhost:8443/api/v1/apis -H 'Content-Type: application/json' -d '{"name":"inventory","context":"/inventory","version":"v1","projectId":"<projectId>"}'`.
2126
- Fetch: `curl -k https://localhost:8443/api/v1/apis/<apiId>`; confirm nested structures.
2227
- List: `curl -k https://localhost:8443/api/v1/projects/<projectId>/apis` to verify pagination metadata and entries.
2328
- Deploy API: `curl -k -X POST https://localhost:8443/api/v1/apis/<apiId>/deploy-revision -H 'Content-Type: application/json' -d '[{"name": "production-deployment","gatewayId": "987e6543-e21b-45d3-a789-426614174999", "displayOnDevportal": true}]'` to trigger API deployment.
29+
- Get API Gateways: `curl -k https://localhost:8443/api/v1/apis/<apiId>/gateways` to retrieve all gateways where the API is deployed; expect JSON array with gateway details (id, name, displayName, vhost, isActive, etc.).

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@ package handler
1919

2020
import (
2121
"errors"
22+
"github.com/gin-gonic/gin"
2223
"log"
2324
"net/http"
2425
"platform-api/src/internal/constants"
2526
"platform-api/src/internal/dto"
2627
"platform-api/src/internal/middleware"
2728
"platform-api/src/internal/service"
2829
"platform-api/src/internal/utils"
29-
30-
"github.com/gin-gonic/gin"
3130
)
3231

3332
type APIHandler struct {
@@ -340,6 +339,36 @@ func (h *APIHandler) DeployAPIRevision(c *gin.Context) {
340339
c.JSON(http.StatusOK, deployments)
341340
}
342341

342+
// GetAPIDeployedGateways handles GET /api/v1/apis/{apiId}/gateways
343+
func (h *APIHandler) GetAPIDeployedGateways(c *gin.Context) {
344+
orgId, exists := middleware.GetOrganizationFromContext(c)
345+
if !exists {
346+
c.JSON(http.StatusUnauthorized, utils.NewErrorResponse(401, "Unauthorized",
347+
"Organization claim not found in token"))
348+
return
349+
}
350+
351+
apiId := c.Param("apiId")
352+
if apiId == "" {
353+
c.JSON(http.StatusBadRequest, utils.NewErrorResponse(400, "Bad Request", "API ID is required"))
354+
return
355+
}
356+
357+
// Get paginated gateways for the API
358+
gatewayListResponse, err := h.apiService.GetGatewaysForAPI(apiId, orgId)
359+
if err != nil {
360+
if errors.Is(err, constants.ErrAPINotFound) {
361+
c.JSON(http.StatusNotFound, utils.NewErrorResponse(404, "Not Found", "API not found"))
362+
return
363+
}
364+
c.JSON(http.StatusInternalServerError, utils.NewErrorResponse(500, "Internal Server Error", "Failed to get API gateways"))
365+
return
366+
}
367+
368+
// Return paginated gateway list
369+
c.JSON(http.StatusOK, gatewayListResponse)
370+
}
371+
343372
// RegisterRoutes registers all API routes
344373
func (h *APIHandler) RegisterRoutes(r *gin.Engine) {
345374
// API routes
@@ -351,5 +380,6 @@ func (h *APIHandler) RegisterRoutes(r *gin.Engine) {
351380
apiGroup.PUT("/:apiId", h.UpdateAPI)
352381
apiGroup.DELETE("/:apiId", h.DeleteAPI)
353382
apiGroup.POST("/:apiId/deploy-revision", h.DeployAPIRevision)
383+
apiGroup.GET("/:apiId/gateways", h.GetAPIDeployedGateways)
354384
}
355385
}

platform-api/src/internal/repository/gateway.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,36 @@ func (r *GatewayRepo) CountActiveTokens(gatewayId string) (int, error) {
287287
err := r.db.QueryRow(query, gatewayId).Scan(&count)
288288
return count, err
289289
}
290+
291+
// GetGatewaysByAPIID retrieves all gateways where the specified API is deployed
292+
func (r *GatewayRepo) GetGatewaysByAPIID(apiID, organizationID string) ([]*model.Gateway, error) {
293+
query := `
294+
SELECT g.uuid, g.organization_uuid, g.name, g.display_name, g.description,
295+
g.vhost, g.is_critical, g.gateway_functionality_type, g.is_active,
296+
g.created_at, g.updated_at
297+
FROM gateways g
298+
INNER JOIN api_deployments ad ON g.uuid = ad.gateway_uuid
299+
WHERE ad.api_uuid = ? AND g.organization_uuid = ?
300+
ORDER BY g.created_at DESC
301+
`
302+
rows, err := r.db.Query(query, apiID, organizationID)
303+
if err != nil {
304+
return nil, err
305+
}
306+
defer rows.Close()
307+
308+
var gateways []*model.Gateway
309+
for rows.Next() {
310+
gateway := &model.Gateway{}
311+
err := rows.Scan(
312+
&gateway.ID, &gateway.OrganizationID, &gateway.Name, &gateway.DisplayName,
313+
&gateway.Description, &gateway.Vhost, &gateway.IsCritical,
314+
&gateway.FunctionalityType, &gateway.IsActive, &gateway.CreatedAt, &gateway.UpdatedAt,
315+
)
316+
if err != nil {
317+
return nil, err
318+
}
319+
gateways = append(gateways, gateway)
320+
}
321+
return gateways, nil
322+
}

platform-api/src/internal/repository/interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type GatewayRepository interface {
6161
GetByUUID(gatewayId string) (*model.Gateway, error)
6262
GetByOrganizationID(orgID string) ([]*model.Gateway, error)
6363
GetByNameAndOrgID(name, orgID string) (*model.Gateway, error)
64+
GetGatewaysByAPIID(apiID, organizationID string) ([]*model.Gateway, error)
6465
List() ([]*model.Gateway, error)
6566
Delete(gatewayID, organizationID string) error
6667
UpdateGateway(gateway *model.Gateway) error

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,58 @@ func (s *APIService) DeployAPIRevision(apiId string, revisionID string,
433433
return deployments, nil
434434
}
435435

436+
// GetGatewaysForAPI retrieves all gateways where the specified API is deployed with pagination
437+
func (s *APIService) GetGatewaysForAPI(apiId, orgId string) (*dto.GatewayListResponse, error) {
438+
// First validate that the API exists and belongs to the organization
439+
apiModel, err := s.apiRepo.GetAPIByUUID(apiId)
440+
if err != nil {
441+
return nil, err
442+
}
443+
if apiModel == nil {
444+
return nil, constants.ErrAPINotFound
445+
}
446+
if apiModel.OrganizationID != orgId {
447+
return nil, constants.ErrAPINotFound
448+
}
449+
450+
// Get all gateways where this API is deployed (without pagination for total count)
451+
gateways, err := s.gatewayRepo.GetGatewaysByAPIID(apiId, orgId)
452+
if err != nil {
453+
return nil, err
454+
}
455+
456+
// Convert models to DTOs
457+
responses := make([]dto.GatewayResponse, 0, len(gateways))
458+
for _, gw := range gateways {
459+
responses = append(responses, dto.GatewayResponse{
460+
ID: gw.ID,
461+
OrganizationID: gw.OrganizationID,
462+
Name: gw.Name,
463+
DisplayName: gw.DisplayName,
464+
Description: gw.Description,
465+
Vhost: gw.Vhost,
466+
IsCritical: gw.IsCritical,
467+
FunctionalityType: gw.FunctionalityType,
468+
IsActive: gw.IsActive,
469+
CreatedAt: gw.CreatedAt,
470+
UpdatedAt: gw.UpdatedAt,
471+
})
472+
}
473+
474+
// Create paginated response
475+
listResponse := &dto.GatewayListResponse{
476+
Count: len(responses),
477+
List: responses,
478+
Pagination: dto.Pagination{
479+
Total: len(responses), // For now, total equals count (no pagination yet)
480+
Offset: 0, // Starting from first item
481+
Limit: len(responses), // Returning all items
482+
},
483+
}
484+
485+
return listResponse, nil
486+
}
487+
436488
// validateDeploymentRequest validates the deployment request
437489
func (s *APIService) validateDeploymentRequest(req *dto.APIRevisionDeployment, orgId string) error {
438490
if req.GatewayID == "" {

platform-api/src/resources/openapi.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,35 @@ paths:
413413
'500':
414414
$ref: '#/components/responses/InternalServerError'
415415

416+
/apis/{apiId}/gateways:
417+
get:
418+
summary: Get gateways for API
419+
description: |
420+
Retrieves all gateways where the specified API is deployed with pagination support.
421+
This endpoint returns a paginated list of gateway instances that currently have the API deployed to them.
422+
Access is validated against the organization in the JWT token.
423+
operationId: GetAPIGateways
424+
tags:
425+
- APIs
426+
- Gateways
427+
parameters:
428+
- $ref: '#/components/parameters/apiID'
429+
responses:
430+
'200':
431+
description: Paginated list of gateways where the API is deployed
432+
content:
433+
application/json:
434+
schema:
435+
$ref: '#/components/schemas/GatewayListResponse'
436+
'400':
437+
$ref: '#/components/responses/BadRequest'
438+
'401':
439+
$ref: '#/components/responses/Unauthorized'
440+
'404':
441+
$ref: '#/components/responses/NotFound'
442+
'500':
443+
$ref: '#/components/responses/InternalServerError'
444+
416445
/gateways:
417446
post:
418447
summary: Register a new gateway

0 commit comments

Comments
 (0)