Skip to content

Expand response schema with validation metadata and add /v1/ API versioning#16

Merged
mcrundo merged 1 commit into
mainfrom
expand-schema
Mar 27, 2026
Merged

Expand response schema with validation metadata and add /v1/ API versioning#16
mcrundo merged 1 commit into
mainfrom
expand-schema

Conversation

@mcrundo
Copy link
Copy Markdown
Owner

@mcrundo mcrundo commented Mar 27, 2026

Summary

  • Expand the response envelope to include is_valid, validation_results (granularity +
    per-component messages), formatted_address, original_address echo, and original_response (raw
    Google API response)
  • Extract verdict, component confirmation levels, and formatted address from Google's response
    (previously discarded)
  • Add /v1/ path prefix to all API Gateway routes for proper API versioning

Before

{
  "line1": "1600 Amphitheatre Pkwy",
  "line2": null,
  "city": "Mountain View",
  "state": "CA",
  "postal_code": "94043-1351",
  "country": "US"
}

After

{
  "is_valid": true,
  "address": {
    "line1": "1600 Amphitheatre Pkwy",
    "line2": null,
    "city": "Mountain View",
    "state": "CA",
    "postal_code": "94043-1351",
    "country": "US"
  },
  "validation_results": {
    "granularity": "premise",
    "messages": [
      {
        "source": "google_maps",
        "code": "street_number.confirmed",
        "text": "Street number confirmed",
        "type": "info"
      }
    ]
  },
  "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043-1351, USA",
  "original_address": {
    "lines": ["1600 Amphitheatre Parkway"],
    "city": "Mountain View",
    "state": "CA",
    "postal_code": "94043",
    "country": "US"
  },
  "original_response": { "result": { "verdict": { "..." }, "address": { "..." }, "geocode": { "..."
} } }
}

Changes

  • models.py — New dataclasses: ValidationMessage, ValidationResults, ParsedResult,
    ValidationResponse
  • parser.py — Extracts verdict, component confirmations, and formatted address from Google's
    response
  • handler.py — Assembles full response envelope with original address echo and raw Google
    response
  • api_gateway.tf — Routes updated to POST /v1/validate, GET /v1/health
  • openapi.yaml — v1.0.0 with new schemas and path prefix
  • README.md — Updated API docs, response example, and field reference table

@github-actions
Copy link
Copy Markdown

Terraform Plan 📖success

Show Plan
aws_apigatewayv2_api.this: Refreshing state... [id=py1sucuxvi]
aws_secretsmanager_secret.google_maps_api_key: Refreshing state... [id=arn:aws:secretsmanager:us-east-2:023179631616:secret:address-validation/dev/google-maps-api-key]
aws_cloudwatch_log_group.health: Refreshing state... [id=/aws/lambda/address-validation-health-dev]
aws_secretsmanager_secret.api_key: Refreshing state... [id=arn:aws:secretsmanager:us-east-2:023179631616:secret:address-validation/dev/api-key]
aws_cloudwatch_log_group.handler: Refreshing state... [id=/aws/lambda/address-validation-handler-dev]
data.aws_iam_policy_document.lambda_assume_role: Reading...
aws_cloudwatch_log_group.api_gateway: Refreshing state... [id=/aws/apigateway/address-validation-dev]
aws_cloudwatch_log_group.authorizer: Refreshing state... [id=/aws/lambda/address-validation-authorizer-dev]
aws_sqs_queue.handler_dlq: Refreshing state... [id=https://sqs.us-east-2.amazonaws.com/023179631616/address-validation-handler-dlq-dev]
data.aws_iam_policy_document.lambda_assume_role: Read complete after 0s [id=2690255455]
aws_iam_role.lambda_exec: Refreshing state... [id=address-validation-lambda-dev]
data.aws_iam_policy_document.lambda_logs: Reading...
data.aws_iam_policy_document.lambda_logs: Read complete after 0s [id=543498868]
data.aws_iam_policy_document.dlq_send: Reading...
aws_cloudwatch_metric_alarm.dlq_depth: Refreshing state... [id=address-validation-dlq-depth-dev]
data.aws_iam_policy_document.dlq_send: Read complete after 0s [id=1518684834]
data.aws_iam_policy_document.authorizer_secrets: Reading...
data.aws_iam_policy_document.authorizer_secrets: Read complete after 0s [id=2856189735]
data.aws_iam_policy_document.secrets_read: Reading...
data.aws_iam_policy_document.secrets_read: Read complete after 0s [id=3213121637]
aws_apigatewayv2_stage.default: Refreshing state... [id=$default]
aws_iam_role_policy.lambda_logs: Refreshing state... [id=address-validation-lambda-dev:cloudwatch-logs]
aws_iam_role_policy.secrets_read: Refreshing state... [id=address-validation-lambda-dev:secrets-read]
aws_iam_role_policy.dlq_send: Refreshing state... [id=address-validation-lambda-dev:dlq-send]
aws_iam_role_policy_attachment.xray: Refreshing state... [id=address-validation-lambda-dev-20260323021610749600000001]
aws_iam_role_policy.authorizer_secrets: Refreshing state... [id=address-validation-lambda-dev:authorizer-secrets-read]
aws_lambda_function.authorizer: Refreshing state... [id=address-validation-authorizer-dev]
aws_lambda_function.health: Refreshing state... [id=address-validation-health-dev]
aws_lambda_function.handler: Refreshing state... [id=address-validation-handler-dev]
aws_apigatewayv2_integration.health: Refreshing state... [id=6ktcygu]
aws_lambda_permission.api_gateway_health: Refreshing state... [id=AllowAPIGatewayInvokeHealth]
aws_lambda_permission.authorizer_invoke: Refreshing state... [id=AllowAPIGatewayInvokeAuthorizer]
aws_apigatewayv2_authorizer.api_key: Refreshing state... [id=64l2kl]
aws_cloudwatch_metric_alarm.authorizer_errors: Refreshing state... [id=address-validation-authorizer-errors-dev]
aws_apigatewayv2_route.health: Refreshing state... [id=8s7aw6n]
aws_cloudwatch_metric_alarm.handler_errors: Refreshing state... [id=address-validation-handler-errors-dev]
aws_cloudwatch_metric_alarm.handler_duration: Refreshing state... [id=address-validation-handler-duration-dev]
aws_cloudwatch_metric_alarm.handler_throttles: Refreshing state... [id=address-validation-handler-throttles-dev]
aws_lambda_permission.api_gateway_handler: Refreshing state... [id=AllowAPIGatewayInvokeHandler]
aws_apigatewayv2_integration.handler: Refreshing state... [id=s8f1dfh]
aws_apigatewayv2_route.validate: Refreshing state... [id=n68uzib]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_apigatewayv2_route.health will be updated in-place
  ~ resource "aws_apigatewayv2_route" "health" {
        id                   = "8s7aw6n"
      ~ route_key            = "GET /health" -> "GET /v1/health"
        # (6 unchanged attributes hidden)
    }

  # aws_apigatewayv2_route.validate will be updated in-place
  ~ resource "aws_apigatewayv2_route" "validate" {
        id                   = "n68uzib"
      ~ route_key            = "POST /validate" -> "POST /v1/validate"
        # (7 unchanged attributes hidden)
    }

  # aws_lambda_function.authorizer will be updated in-place
  ~ resource "aws_lambda_function" "authorizer" {
        id                             = "address-validation-authorizer-dev"
      ~ last_modified                  = "2026-03-23T02:41:34.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "Ildp4393rr80qhPHc0UcciMOvwe3XklmU72GI7R/Lg8="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # aws_lambda_function.handler will be updated in-place
  ~ resource "aws_lambda_function" "handler" {
        id                             = "address-validation-handler-dev"
      ~ last_modified                  = "2026-03-23T02:42:07.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "Ildp4393rr80qhPHc0UcciMOvwe3XklmU72GI7R/Lg8="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (5 unchanged blocks hidden)
    }

  # aws_lambda_function.health will be updated in-place
  ~ resource "aws_lambda_function" "health" {
        id                             = "address-validation-health-dev"
      ~ last_modified                  = "2026-03-23T02:41:28.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "Ildp4393rr80qhPHc0UcciMOvwe3XklmU72GI7R/Lg8="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 5 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Triggered by @mcrundo in commit 4ffcf73

@github-actions
Copy link
Copy Markdown

Terraform Plan 📖success

Show Plan
aws_cloudwatch_log_group.api_gateway: Refreshing state... [id=/aws/apigateway/address-validation-dev]
data.aws_iam_policy_document.lambda_assume_role: Reading...
aws_sqs_queue.handler_dlq: Refreshing state... [id=https://sqs.us-east-2.amazonaws.com/023179631616/address-validation-handler-dlq-dev]
aws_cloudwatch_log_group.health: Refreshing state... [id=/aws/lambda/address-validation-health-dev]
aws_secretsmanager_secret.api_key: Refreshing state... [id=arn:aws:secretsmanager:us-east-2:023179631616:secret:address-validation/dev/api-key]
aws_secretsmanager_secret.google_maps_api_key: Refreshing state... [id=arn:aws:secretsmanager:us-east-2:023179631616:secret:address-validation/dev/google-maps-api-key]
aws_apigatewayv2_api.this: Refreshing state... [id=py1sucuxvi]
data.aws_iam_policy_document.lambda_assume_role: Read complete after 0s [id=2690255455]
aws_cloudwatch_log_group.authorizer: Refreshing state... [id=/aws/lambda/address-validation-authorizer-dev]
aws_cloudwatch_log_group.handler: Refreshing state... [id=/aws/lambda/address-validation-handler-dev]
aws_iam_role.lambda_exec: Refreshing state... [id=address-validation-lambda-dev]
data.aws_iam_policy_document.secrets_read: Reading...
data.aws_iam_policy_document.secrets_read: Read complete after 0s [id=3213121637]
data.aws_iam_policy_document.authorizer_secrets: Reading...
data.aws_iam_policy_document.authorizer_secrets: Read complete after 0s [id=2856189735]
data.aws_iam_policy_document.dlq_send: Reading...
aws_cloudwatch_metric_alarm.dlq_depth: Refreshing state... [id=address-validation-dlq-depth-dev]
data.aws_iam_policy_document.dlq_send: Read complete after 0s [id=1518684834]
data.aws_iam_policy_document.lambda_logs: Reading...
data.aws_iam_policy_document.lambda_logs: Read complete after 0s [id=543498868]
aws_apigatewayv2_stage.default: Refreshing state... [id=$default]
aws_iam_role_policy.secrets_read: Refreshing state... [id=address-validation-lambda-dev:secrets-read]
aws_iam_role_policy_attachment.xray: Refreshing state... [id=address-validation-lambda-dev-20260323021610749600000001]
aws_iam_role_policy.dlq_send: Refreshing state... [id=address-validation-lambda-dev:dlq-send]
aws_iam_role_policy.lambda_logs: Refreshing state... [id=address-validation-lambda-dev:cloudwatch-logs]
aws_iam_role_policy.authorizer_secrets: Refreshing state... [id=address-validation-lambda-dev:authorizer-secrets-read]
aws_lambda_function.handler: Refreshing state... [id=address-validation-handler-dev]
aws_lambda_function.health: Refreshing state... [id=address-validation-health-dev]
aws_lambda_function.authorizer: Refreshing state... [id=address-validation-authorizer-dev]
aws_lambda_permission.api_gateway_health: Refreshing state... [id=AllowAPIGatewayInvokeHealth]
aws_apigatewayv2_integration.health: Refreshing state... [id=6ktcygu]
aws_cloudwatch_metric_alarm.authorizer_errors: Refreshing state... [id=address-validation-authorizer-errors-dev]
aws_lambda_permission.authorizer_invoke: Refreshing state... [id=AllowAPIGatewayInvokeAuthorizer]
aws_apigatewayv2_authorizer.api_key: Refreshing state... [id=64l2kl]
aws_apigatewayv2_integration.handler: Refreshing state... [id=s8f1dfh]
aws_lambda_permission.api_gateway_handler: Refreshing state... [id=AllowAPIGatewayInvokeHandler]
aws_cloudwatch_metric_alarm.handler_throttles: Refreshing state... [id=address-validation-handler-throttles-dev]
aws_cloudwatch_metric_alarm.handler_errors: Refreshing state... [id=address-validation-handler-errors-dev]
aws_cloudwatch_metric_alarm.handler_duration: Refreshing state... [id=address-validation-handler-duration-dev]
aws_apigatewayv2_route.health: Refreshing state... [id=8s7aw6n]
aws_apigatewayv2_route.validate: Refreshing state... [id=n68uzib]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_apigatewayv2_route.health will be updated in-place
  ~ resource "aws_apigatewayv2_route" "health" {
        id                   = "8s7aw6n"
      ~ route_key            = "GET /health" -> "GET /v1/health"
        # (6 unchanged attributes hidden)
    }

  # aws_apigatewayv2_route.validate will be updated in-place
  ~ resource "aws_apigatewayv2_route" "validate" {
        id                   = "n68uzib"
      ~ route_key            = "POST /validate" -> "POST /v1/validate"
        # (7 unchanged attributes hidden)
    }

  # aws_lambda_function.authorizer will be updated in-place
  ~ resource "aws_lambda_function" "authorizer" {
        id                             = "address-validation-authorizer-dev"
      ~ last_modified                  = "2026-03-23T02:41:34.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "mKXj0whjlba5skjiDl50kMaO92MbYGbN0U4z2Yv8v8I="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # aws_lambda_function.handler will be updated in-place
  ~ resource "aws_lambda_function" "handler" {
        id                             = "address-validation-handler-dev"
      ~ last_modified                  = "2026-03-23T02:42:07.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "mKXj0whjlba5skjiDl50kMaO92MbYGbN0U4z2Yv8v8I="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (5 unchanged blocks hidden)
    }

  # aws_lambda_function.health will be updated in-place
  ~ resource "aws_lambda_function" "health" {
        id                             = "address-validation-health-dev"
      ~ last_modified                  = "2026-03-23T02:41:28.000+0000" -> (known after apply)
      ~ source_code_hash               = "nZDM+wtqa//F8Ln7kn3VTfj51rFMg3BxwVUUMvNdCzk=" -> "mKXj0whjlba5skjiDl50kMaO92MbYGbN0U4z2Yv8v8I="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 5 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Triggered by @mcrundo in commit 71d8095

@mcrundo mcrundo merged commit c57d1f7 into main Mar 27, 2026
3 checks passed
@mcrundo mcrundo deleted the expand-schema branch March 27, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant