Skip to content

feat(apigateway): persist API key tags and add GetApiKey route#1677

Open
awuzi wants to merge 2 commits into
floci-io:mainfrom
awuzi:feat/apigateway-apikey-tags
Open

feat(apigateway): persist API key tags and add GetApiKey route#1677
awuzi wants to merge 2 commits into
floci-io:mainfrom
awuzi:feat/apigateway-apikey-tags

Conversation

@awuzi

@awuzi awuzi commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Fixes the two API Gateway API-key gaps reported in #1676:

  • CreateApiKey now persists the request tags and returns them from CreateApiKey, GetApiKey and GetApiKeys.
  • Adds the missing GetApiKey route (GET /apikeys/{apiKeyId}), delegating to the existing service.getApiKey(...). It omits value unless includeValue=true, and returns a JSON NotFoundException (404) for unknown keys.

Changes

  • model/ApiKey.java — add a tags map (mirrors RestApi).
  • ApiGatewayService#createApiKey — read tags from the request (same pattern as createRestApi).
  • ApiGatewayController — serialize tags in toApiKeyNode; add the GET /apikeys/{apiKeyId} route.
  • ApiGatewayApiKeyIntegrationTest — covers tag persistence, GetApiKey (with/without value), listing, and 404.

Notes

Backward-compatible: keys persisted before this change deserialize with an empty tags map (@JsonIgnoreProperties(ignoreUnknown = true) + default field value).

Closes #1676

CreateApiKey now stores the request tags and returns them from CreateApiKey, GetApiKey and GetApiKeys. Adds the missing GET /apikeys/{apiKeyId} route, which omits the value unless includeValue=true and returns 404 when the key is unknown.
Copilot AI review requested due to automatic review settings July 1, 2026 14:04
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR closes two API Gateway gaps: it persists tags on CreateApiKey and adds the missing GET /apikeys/{apiKeyId} route, returning 404 for unknown keys and omitting the secret value unless includeValue=true.

  • ApiKey.java gains a tags: Map<String,String> field with a default empty map and a null-guarding setter, making the change backward-compatible with keys persisted before this change.
  • ApiGatewayController adds the GET /apikeys/{apiKeyId} handler (delegating to the existing service method) and updates toApiKeyNode to always emit "tags": {}, matching the AWS wire protocol.
  • ApiGatewayService#createApiKey reads tags from the request body using a type-safe pattern-match cast, consistent with the createRestApi pattern already in the codebase.

Confidence Score: 5/5

Safe to merge — the change is narrow, backward-compatible, and all newly-added logic follows established patterns in the codebase.

The model change is backward-compatible (default field value + @JsonIgnoreProperties), the tag-parsing in the service mirrors the existing createRestApi pattern, and toApiKeyNode correctly emits "tags": {} unconditionally. The new GET /apikeys/{apiKeyId} handler follows the same thin-controller pattern used by every other GET-by-ID endpoint in the file.

The integration test file only validates via raw HTTP; adding an AWS SDK client assertion later would improve confidence in wire-level compatibility.

Important Files Changed

Filename Overview
src/main/java/io/github/hectorvent/floci/services/apigateway/model/ApiKey.java Adds a tags Map field with a safe default (new HashMap<>()) and a null-guarding setter; backward-compatible with previously-persisted keys via @JsonIgnoreProperties.
src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayService.java Reads tags from the create request using a type-safe pattern-match cast, copies entries into a fresh HashMap, and passes it to the model — consistent with existing patterns in the service.
src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayController.java Adds GET /apikeys/{apiKeyId} delegating to the existing service method; toApiKeyNode unconditionally emits "tags": {} and fills it when non-empty, matching the AWS wire protocol.
src/test/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayApiKeyIntegrationTest.java Covers tag persistence, GetApiKey with/without includeValue, list, and 404; tests use raw RestAssured rather than the AWS SDK, leaving SDK wire-compatibility unverified.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant ApiGatewayController
    participant ApiGatewayService
    participant apiKeyStore

    Note over Client,apiKeyStore: CreateApiKey (with tags)
    Client->>ApiGatewayController: "POST /apikeys {name, enabled, tags}"
    ApiGatewayController->>ApiGatewayService: createApiKey(region, request)
    ApiGatewayService->>ApiGatewayService: parse tags from request
    ApiGatewayService->>apiKeyStore: put(apiKeyGlobalKey, apiKey)
    ApiGatewayService-->>ApiGatewayController: ApiKey (with tags)
    ApiGatewayController-->>Client: "201 {id, name, enabled, value, tags}"

    Note over Client,apiKeyStore: GetApiKey (new route)
    Client->>ApiGatewayController: "GET /apikeys/{apiKeyId}[?includeValue=true]"
    ApiGatewayController->>ApiGatewayService: getApiKey(region, apiKeyId)
    ApiGatewayService->>apiKeyStore: get(apiKeyGlobalKey)
    alt key found
        apiKeyStore-->>ApiGatewayService: Optional[ApiKey]
        ApiGatewayService-->>ApiGatewayController: ApiKey
        ApiGatewayController->>ApiGatewayController: toApiKeyNode (remove value if !includeValue)
        ApiGatewayController-->>Client: "200 {id, name, enabled, tags[, value]}"
    else key not found
        apiKeyStore-->>ApiGatewayService: Optional.empty()
        ApiGatewayService-->>ApiGatewayController: throws AwsException(NotFoundException, 404)
        ApiGatewayController-->>Client: "404 {__type: NotFoundException, message}"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant ApiGatewayController
    participant ApiGatewayService
    participant apiKeyStore

    Note over Client,apiKeyStore: CreateApiKey (with tags)
    Client->>ApiGatewayController: "POST /apikeys {name, enabled, tags}"
    ApiGatewayController->>ApiGatewayService: createApiKey(region, request)
    ApiGatewayService->>ApiGatewayService: parse tags from request
    ApiGatewayService->>apiKeyStore: put(apiKeyGlobalKey, apiKey)
    ApiGatewayService-->>ApiGatewayController: ApiKey (with tags)
    ApiGatewayController-->>Client: "201 {id, name, enabled, value, tags}"

    Note over Client,apiKeyStore: GetApiKey (new route)
    Client->>ApiGatewayController: "GET /apikeys/{apiKeyId}[?includeValue=true]"
    ApiGatewayController->>ApiGatewayService: getApiKey(region, apiKeyId)
    ApiGatewayService->>apiKeyStore: get(apiKeyGlobalKey)
    alt key found
        apiKeyStore-->>ApiGatewayService: Optional[ApiKey]
        ApiGatewayService-->>ApiGatewayController: ApiKey
        ApiGatewayController->>ApiGatewayController: toApiKeyNode (remove value if !includeValue)
        ApiGatewayController-->>Client: "200 {id, name, enabled, tags[, value]}"
    else key not found
        apiKeyStore-->>ApiGatewayService: Optional.empty()
        ApiGatewayService-->>ApiGatewayController: throws AwsException(NotFoundException, 404)
        ApiGatewayController-->>Client: "404 {__type: NotFoundException, message}"
    end
Loading

Reviews (2): Last reviewed commit: "fix(apigateway): always emit tags object..." | Re-trigger Greptile

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes API Gateway API key compatibility gaps by persisting tags on CreateApiKey and adding the missing GetApiKey route (GET /apikeys/{apiKeyId}), aiming to match AWS REST-JSON behavior and SDK expectations.

Changes:

  • Add tags to the ApiKey model and persist them during CreateApiKey.
  • Add GET /apikeys/{apiKeyId} with includeValue support (omit value unless requested).
  • Add integration coverage for tag persistence, retrieval, listing, and not-found behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/test/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayApiKeyIntegrationTest.java Adds integration tests for tag persistence and the new GetApiKey route.
src/main/java/io/github/hectorvent/floci/services/apigateway/model/ApiKey.java Extends the API key model with a tags map and null-safe setter.
src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayService.java Reads tags from the create request and persists them with the API key.
src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayController.java Adds GET /apikeys/{apiKeyId} and serializes tags in API key JSON responses.

Address review feedback: toApiKeyNode always emits "tags" (AWS returns "tags": {} even when empty); createApiKey coerces tag keys/values to String instead of an unchecked cast; the integration test initialises the shared apiKeyId to a sentinel and asserts the JSON error body on the 404 path.
@hectorvent hectorvent added apigateway Amazon API Gateway (REST/v1) feature labels Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apigateway Amazon API Gateway (REST/v1) feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] apigateway: CreateApiKey drops "tags" and GetApiKey is not implemented (404)

3 participants