I am currently utilizing Cloudrun in GCP and am interested in summarizing the created APIs with API Gateway. To achieve this, a Swagger/OpenAPI v2 document needs to be generated containing the google-generated URLs for the Cloudrun Services.
How can I extract these URLs from the Pulumi Output and incorporate them into the swagger file for uploading as the API Config?
Initially, I thought of using Moustache. However, I am now experimenting with raw JSON and have not been successful so far. Despite trying apply()
and interpolate
, I always end up with [object Object]
instead of the actual URL of the deployed service.
"x-google-backend": {
"address": {
"[object Object]":null
},
"path_translation":"APPEND_PATH_TO_ADDRESS"
}
What am I overlooking here?
Is there a way to make it work directly with Moustache without dealing with deserialized Swagger?
Sample code:
A Basic Swagger File my-spec.yaml
swagger: '2.0'
info:
title: Demo for URL Replacement
version: 0.0.1
schemes:
- https
paths:
/users:
post:
summary: Registers a new user to the service
operationId: createUser
x-google-backend:
address: {{{apiUsersUrl}}} # Output URL from CloudRun, in moustache format
path_translation: APPEND_PATH_TO_ADDRESS
responses:
201:
description: Success
security:
- api_key: []
securityDefinitions:
api_key:
type: apiKey
name: x-api-key
in: header
The file to create the new API Config.
import * as pulumi from '@pulumi/pulumi';
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import { Spec } from '../types/Swagger';
export function buildApiSpecJS(usersUrl: pulumi.Output<string>) {
const specFile = fs.readFileSync(`${__dirname}/my-spec.yaml`, 'utf8');
const specTemplate= yaml.load(specFile) as Spec;
usersUrl.apply((url) => {
let pathName: keyof typeof specTemplate.paths;
// eslint-disable-next-line guard-for-in
for (pathName in specTemplate.paths) {
const path = specTemplate.paths[pathName];
let operation: keyof typeof path;
for (operation in path) {
if (path[operation] !== '$ref') {
const address: string = path[operation]['x-google-backend']?.address;
if (address === '{{{apiUsersUrl}}}') {
path[operation]['x-google-backend'].address = pulumi.interpolate`${url}`;
}
}
}
}
fs.writeFileSync(`${__dirname}/testfile.json`, JSON.stringify(specTemplate));
});
}
The Spec
from types is copied and amended from DefinitelyTyped Definition
// Changes:
// - Operation is edited to add the Google Backend
export interface GoogleBackend {
address: string;
jwt_audience?: string;
disable_auth?: boolean;
path_translation?: string; // [ APPEND_PATH_TO_ADDRESS | CONSTANT_ADDRESS ]
deadline?: string;
protocol?: string; // [ http/1.1 | h2 ]
};
//
///// .... Copied Types ....
// ----------------------------- Operation -----------------------------------
export interface Operation {
responses: { [responseName: string]: Response | Reference };
summary?: string | undefined;
description?: string | undefined;
externalDocs?: ExternalDocs | undefined;
operationId?: string | undefined;
produces?: string[] | undefined;
consumes?: string[] | undefined;
parameters?: Array<Parameter | Reference> | undefined;
schemes?: string[] | undefined;
deprecated?: boolean | undefined;
security?: Array<{ [securityDefinitionName: string]: string[] }> | undefined;
tags?: string[] | undefined;
'x-google-backend': GoogleBackend | undefined; // Added
}
//
///// Copied Types continue....
//