Generating Pulumi Outputs for exporting as an external configuration file

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....
//

Answer №1

After careful consideration, I decided to utilize DomainMapping and DNS for the solution. By leveraging DomainMapping, I was able to establish a consistent and predictable name for the Cloud Run service in each environment, such as api-users.dev.example.com.

This allowed me to anticipate the name beforehand and seamlessly incorporate it into the Moustache replacements within the API Spec.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue encountered in Angular app-routing module.ts: Type error TS2322: The type '"enabled"' cannot be assigned to type 'InitialNavigation | undefined'

When I recently updated my project from Angular 11 to 14, I encountered the following error when running "ng serve". Error: src/app/app-routing.module.ts:107:7 - error TS2322: Type '"enabled"' is not assignable to type 'InitialNavigation | u ...

Attempting to incorporate alert feedback into an Angular application

I am having trouble referencing the value entered in a popup input field for quantity. I have searched through the documentation but haven't found a solution yet. Below is the code snippet from my .ts file: async presentAlert() { const alert = awa ...

The error message "TypeError: (0 , N.createContext) is not a function" indicates that

I'm currently in the process of developing a cutting-edge application using Next.js 14, TypeScript, and Telegram Open Network. However, I've hit a roadblock while attempting to incorporate the TONConnectUIProvider at the root of my app. Upon run ...

Use contextual type when determining the return type of a function, rather than relying solely on

When using Typescript 2.2.2 (with the strictNullChecks option set to true), I encountered an unexpected behavior. Is this a bug or intentional? interface Fn { (value: any): number; } var example1: Fn = function(value) { if (value === -1) { ...

How can the value of a number in Angular be changed without altering its original value?

Imagine having the initial number 100. If I enter 50 in another input, it should add 50 to 100. However, if I then change the value from 50 to 80, the total should be 180 and not 230. The goal is always to add numbers to the original sum, not the new valu ...

Combining two sets of data into one powerful tool: ngx-charts for Angular 2

After successfully creating a component chart using ngx-charts in angular 2 and pulling data from data.ts, I am now looking to reuse the same component to display a second chart with a different data set (data2.ts). Is this even possible? Can someone guide ...

Can someone help me create Three.js types using the frontend option I choose?

I'm currently developing a user-friendly browser application for editing shaders in three.js using react-three-fiber. I want to enhance the functionality by allowing users to add additional uniforms to the ShaderMaterial. However, I do not want to exp ...

Animating sprites using TypeScript

I've been tackling the development of a small Mario game lately. However, I'm facing some difficulty when it comes to animating sprites. For instance, I have a mario.gif file featuring running Mario (although he's not actually running in th ...

Issue in Angular Material: The export 'MaterialComponents' could not be located in './material/material.module'

I'm relatively new to Angular and I am encountering some difficulties when trying to export a material module. The error message that appears is as follows: (Failed to compile.) ./src/app/app.module.ts 17:12-30 "export 'MaterialComponents&ap ...

How can the NavBar be refreshed once a user logs in?

I recently followed a helpful guide on implementing a login system in my React TS application. However, I encountered an issue with the NavBar component within my app compared to how it was coded in the App.tsx file of the guide. Specifically, I found it c ...

Retrieving class properties in typescript

I am working with a class that has numerous methods, which I refer to as myClass. When calling it, the syntax is as follows: myClass[key]() Is there a way to retrieve the valid values for key? I tried using keyof myClass, but received an error message st ...

Handling a change event for a mat-datepicker in Angular 7 can be tricky, especially when its value is tied to an optional input parameter. Let's dive into how to

I've recently started working with angular development and encountered a challenge with a mat-datepicker. The value of the datepicker is connected to filterDate using [(ngModel)] as an @Input() parameter. I have implemented a handleChange event that e ...

Issue with Typescript in react: JSX element lacks construct or call signatures

After upgrading TypeScript, I encountered the error mentioned above in one of my components. In that component's render method, I have the following code: render() { const Tag = props.link ? 'a' : 'div'; return ( < ...

Commit to calculating the total sum of each element using AngularJS

Trying to implement a like counter using Facebook's GRAPH API. I have a list of object IDs and for each ID, I make an API call to retrieve the number of likes and calculate a total. The issue arises as the API call returns a promise, causing only one ...

Leveraging Json data in Angular components through parsing

I am currently developing an angular application where I need to retrieve and process data from JSON in two different steps. To start, I have a JSON structure that is alphabetically sorted as follows: { "1": "Andy", "2": &qu ...

Error encountered with structured array of objects in React Typescript

What is the reason for typescript warning me about this specific line of code? <TimeSlots hours={[{ dayIndex: 1, day: 'monday', }]}/> Can you please explain how I can define a type in JSX? ...

How to handle multiple formData input in NestJS controller

How can I create a controller in Nest.js that accepts two form-data inputs? Here is my Angular service code: public importSchema(file: File, importConfig: PreviewImportConfig): Observable<HttpEvent<SchemaParseResponse>> { const formData = ...

displaying post data in the URL address bar

During the development of my portal using angular 5, everything was running smoothly in the testing environment. However, due to production requirements, I made some changes to access modifiers from private to public. This modification has caused issues in ...

Using Angular2 - How to pass the router parameter as a variable in ngForm

Struggling to pass a router param (id) to an ngForm and then to an event emitter. I am able to retrieve the id from the router successfully, but when trying to assign it to my singleOpenHome object, I encounter an undefined error: @Input() singleOpenHome: ...

Deactivating Bootstrap Modal in Angular

Looking for advice on managing a Bootstrap Modal in Angular 7 I have a Form inside a Bootstrap Modal that I need to reset when the modal is closed (by clicking outside of it). Despite searching on Google, I haven't been able to find a solution. Any ...