I am trying to deploy a GCP API Gateway config with terraform. The OpenAPI document is defined inside the tf file, since I need to use variables for the backend URLs.
When I use wildcards in my paths (/devices/{deviceID}), the deployment produces an error. Without wildcards (/device) it works without issues.
This is the resource specification with wildcards:
resource "google_api_gateway_api_config" "device_management" {
provider = google-beta
project = var.project_id
api = google_api_gateway_api.device_management.api_id
api_config_id_prefix = "${google_api_gateway_api.device_management.api_id}-"
gateway_config {
backend_config {
google_service_account = google_service_account.device_registration.id
}
}
openapi_documents {
document {
path = "${google_api_gateway_api.device_management.api_id}_api_spec.yaml"
contents = base64encode(
jsonencode(
{
swagger : "2.0"
info : {
title : "Device Registration API"
description : "Register devices and get their private keys"
version : "0.0.1"
}
schemes : ["https"]
produces : ["application/json"]
x-google-allow : "configured"
securityDefinitions : {
api_key : {
type : "apiKey"
name : "apiKey"
in : "query"
}
oauth2 : {
authorizationUrl : ""
flow : "implicit"
type : "oauth2"
x-google-issuer : google_service_account.device_registration.email
x-google-jwks_uri : "https://www.googleapis.com/robot/v1/metadata/x509/${google_service_account.device_registration.email}"
x-google-audiences : "device-registration"
}
}
security : [
{ oauth2 : [] }
]
paths : {
"/devices/{deviceID}" : {
post : {
summary : "Register a new device"
operationId : "registerDevice"
x-google-backend : {
address : google_cloudfunctions_function.device_management_register_device.https_trigger_url
}
responses : {
201 : {
description : "Device registered succesfully"
schema : {
type : "string"
}
}
}
}
}
}
}
)
)
}
}
When deploying this I get the following error:
Error: Error creating ApiConfig: googleapi: Error 400: Cannot convert to service config.
│ 'location: "unknown location"
│ kind: ERROR
│ message: "http: undefined field \'deviceID\' on message \'google.protobuf.Empty\'."
│
│ location: "unknown location"
│ kind: ERROR
│ message: "http: undefined field \'deviceID\' on message \'google.protobuf.Empty\'."
│
│ location: "device-registration_api_spec.yaml"
│ message: "apiKey \'apiKey\' is ignored. Only apiKey with \'name\' as \'key\' and \'in\' as \'query\', or \'name\' as \'api_key\' and \'in\' as \'query\', or \'name\'as \'x-api-key\' and \'in\' as \'header\' are supported"
│
│ location: "device-registration_api_spec.yaml: Operation \'post\' in path \'/devices/{deviceID}\'"
│ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : \'apiKey\'."
│
│ location: "device-registration_api_spec.yaml: Operation \'get\' in path \'/devices/{deviceID}/key\'"
│ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : \'apiKey\'."
│ '
│ com.google.apps.framework.request.BadRequestException: Cannot convert to service config.
│ 'location: "unknown location"
│ kind: ERROR
│ message: "http: undefined field \'deviceID\' on message \'google.protobuf.Empty\'."
│
│ location: "unknown location"
│ kind: ERROR
│ message: "http: undefined field \'deviceID\' on message \'google.protobuf.Empty\'."
│
│ location: "device-registration_api_spec.yaml"
│ message: "apiKey \'apiKey\' is ignored. Only apiKey with \'name\' as \'key\' and \'in\' as \'query\', or \'name\' as \'api_key\' and \'in\' as \'query\', or \'name\'as \'x-api-key\' and \'in\' as \'header\' are supported"
│
│ location: "device-registration_api_spec.yaml: Operation \'post\' in path \'/devices/{deviceID}\'"
│ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : \'apiKey\'."
│
│ location: "device-registration_api_spec.yaml: Operation \'get\' in path \'/devices/{deviceID}/key\'"
│ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : \'apiKey\'."
│ '
│
│ with module.iot_backend.google_api_gateway_api_config.device_management,
│ on ../../modules/iot_backend/device_management.tf line 92, in resource "google_api_gateway_api_config" "device_management":
│ 92: resource "google_api_gateway_api_config" "device_management" {
│
╵
How can I get this to work with wildcards?
Based from your error logs, you did not define the deviceID
inside a parameter section or block. Add a parameters section for the deviceID
parameter. Here is an example:
paths:
/users/{userId}:
get:
summary: Gets a user by ID.
parameters:
- in: path
name: userId
type: integer
required: true
description: Numeric ID of the user to get.
In your case, it should be like this:
paths : {
"/devices/{deviceID}" : {
post : {
summary : "Register a new device"
operationId : "registerDevice"
parameters : [
{
in : "path",
name : "deviceID",
type : "string",
required : "true"
}
],
x-google-backend : {
address : google_cloudfunctions_function.device_management_register_device.https_trigger_url
}
responses : {
201 : {
description : "Device registered succesfully"
schema : {
type : "string"
}
}
}
}
}
}
You may refer to these documentation, OpenAPI spec and Swagger, for more information.