What is the best way to incorporate a .json configuration into the environment.ts file and access an API with Angular

I need to import a Json file from the assets folder containing URLs like the following:

config.json:

{
    "url1": "https://jsonplaceholder.typicode.com/posts",
    
    "url2" : "https://reqres.in/api/users",
    
    "url3":"https://fakerestapi.azurewebsites.net/api/Authors"
}

Instead of hardcoding the URLs, I want to import them from the Json file. However, I am unsure about how to do this precisely.

Any advice or scenarios would be greatly appreciated. The issues I am facing are as follows:

1. How can I import the Json file into environment.ts so that a service can consume the API?

2. If I import the file, it needs to be the same for both production and local development environments (dev).

What I desire :

I have a configuration file with URL's stored in a .json file within the assets folder. Instead of loading environments.prod or .ts, I want to load my Json file config and run my application based on that.

What I have done:

Below is the content of my Json file placed in the asset folder:

{
    "baseUrl": "https://jsonplaceholder.typicode.com/",
    "baseUrl2": "https://reqres.in/api/users"
}

ConfigServiceService.ts for storing the configuration file:

public _config: Object;

constructor(public http:Http) { }

getData(){
   debugger;
   return this.http.get("./assets/config.json").pipe(map(res =>  res.json()));
}

Following this, I created a ServiceProviderService.ts for calling the service file:

configData:any;


constructor(public http:Http,public config:ConfigServiceService) {

}

jsonData(){
   debugger;
   return this.configData;
}

ngOnInit(){
  debugger;
  this.config.getData().subscribe(res =>{
     console.log(res);
     this.configData = res;
  });


}

app.component.ts

 title = 'sample';
 constructor(public serv :ServiceProviderService){
      this.serv.jsonData();
 }

I am having trouble retrieving the Json data. If I put the logic inside the constructor in ServiceProviderService.ts, then I get undefined.

Note: If there are multiple URLs, each URL should be distributed to separate service files. For example, one base URL for one service file and another base URL for another file. How can I achieve this?

https://stackblitz.com/edit/read-local-json-file-5zashx

In app.component.ts, I am encountering issues with getting undefined data.

https://i.sstatic.net/XnUMa.png

Answer №1

If you have static strings stored in a JSON file within the /assets directory and not on the server, there is no need to use http.get.
The http protocol is typically used to retrieve data from JSON files located on a server or backend, rather than from client-side folders.
Simply import the JSON file whenever needed, similar to how DTOs are imported. Utilize Typescript's ES6 import statement along with export within the JSON file.

assets/config.ts

export const URLS = Object({

     "url1": "https://jsonplaceholder.typicode.com/posts",

     "url2" : "https://reqres.in/api/users",

     "url3":"https://fakerestapi.azurewebsites.net/api/Authors"
})

Then, in any part of your code (components, directives, services, classes, interfaces, etc ...)

import { URLS } from 'assets/config.ts';

....

this.url1 = URLS.url1;

//or

let url1 = URL.url1;

You can now use this.url1 in any API call within http.get, for example:

 this.http.get(`${this.url1}`, { headers: this.getHeaders(token) });

or

 this.http.get(`${url1}`, { headers: this.getHeaders(token) }) // where url1 could be a variable or method parameter, etc...

That concludes it

Answer №2

One way to access a json file stored in assets is by using the required method 🤔

The path to the json file is /assets/urls.json 📄

{
  "urls": {
    "dev": "dev.com",
    "prod": "prod.com"
  }
}

In the env.ts file:

const { urls } = require("../assets/urls.json");

export const environment: IEnv = {
  production: false,
  baseUrl: urls.dev
};

And in the env.prod.ts file:

const { urls } = require("../assets/urls.json");
export const environment: IEnv = {
  production: true,
  baseUrl: urls.prod
};

🚨 In order to make this work, remember to install npm i @types/node and update your tsconfig.app.json as shown below

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "types": ["node"]
  },
  "exclude": ["test.ts", "**/*.spec.ts"]
}

Answer №3

One solution is to define constants for each URL within the environment file. In this particular situation, there may not be a need to store them in a separate JSON file. When deploying to production, simply update the default configurations property in angular.json to use the same environment file.

Answer №4

If you want to read a Json file using HttpClient, one approach is to create a service for it.

export class SettingService  {

  constructor(private http: HttpClient) {

  }

  public getJSON(file): Observable<any> {
      return this.http.get("./assets/configs/" + file + ".json");
  }
  public getSetting(){
      // perform other actions with setting data here
  }
}

Instead of storing URLs in environment.ts and risking losing them on page refresh, consider saving them to session storage or local storage.

For more information, check out this Stack Overflow thread about reading a json file after building in Angular

Answer №5

    import { environment } from '../../../environments/environment';

    domain :string = environment.domain;

    if(!!environment) {
        if(environment.qa) {
          "url1": "https://jsonplaceholder.typicode.com/posts",
        }
        if(environment.dev) {
           "url2" : "https://reqres.in/api/users",
        } 
      }

Make sure to include the baseUrl property from the asset folder into your service file and follow the provided instructions for execution.

https://alligator.io/angular/environment-variables/

To gain a better understanding of environment variables in Angular, please refer to the URL above.

Answer №6

To streamline the process, I suggest creating a node script named populateDynamicUrls.js. This script will be responsible for extracting values from a JSON file and updating the environment.ts file accordingly based on the specific environment. After setting up the script, your angular build command can be simplified to:

node populateDynamicUrls.js && ng run build
. Similarly, for running the development server, you can use:
node populateDynamicUrls.js && ng run serve

Answer №7

To import a JSON file, follow these steps:

  1. Place config.json in the assets folder.
  2. Open the typings.d.ts file and add the following code:
    declare module "*.json" {
        const value: any;
        export default value;
    }
  1. In your tsconfig.json, under "typeRoots", include the path to the typings.d.ts file:
"typeRoots": [
      "node_modules/@types", "./src/typings.d.ts"
],
  1. Import the config.json into your environment file like this:
import * as config from '../assets/config.json';

export const environment = {
  baseUrl: config.default.url1,
  production: true
};

That's it! Best of luck!

Answer №8

After some tinkering, I found a solution that worked for me. My aim was to have an "API URL" available based on whether we were in Debug or Production mode.

To accomplish this, I made adjustments to two existing .ts files:

  • src\environments\environment.prod.ts
  • src\environments\environment.ts

Each file now had a configuration setting like the following:

export const environment = {
  production: false,
  apiUrl: "http://localhost:53104"
};

The main.ts file already handled reading the environment object and using environment.production. I simply added code to also handle environment.apiUrl:

export function getAPIUrl() {
  console.log("API URL: " + environment.apiUrl);
  return environment.apiUrl;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] },
  { provide: 'API_URL', useFactory: getAPIUrl, deps: [] }
];

. . .

platformBrowserDynamic(providers).bootstrapModule(AppModule)
   .catch(err => console.log(err));

This setup allowed me to access the "API_URL" value in my components, such as in the example below:

export class FetchDataComponent {
  public forecasts: WeatherForecast[];

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string, @Inject('API_URL') APIUrl: string) {
    http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
      this.forecasts = result;
    }, error => console.error(error));

    console.log("FetchDataComponent, URL: " + APIUrl);
  }
}

Upon checking the Output window, I could see my URL displayed when the page loaded.

FetchDataComponent, URL: http://localhost:53104

It felt like a simple yet effective approach with minimal additional code compared to other solutions I came across.

Alternatively, one could skip the "API_URL" provider altogether and directly import the environment variable in components:

import { environment } from '../../environments/environment';

Then accessing the value is straightforward:

console.log("FetchData, URL: " + environment.apiUrl);  

Problem solved!

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

Error: Cannot access collection property of dbObject

I've been working on fetching data from a database, but I've hit a roadblock. I keep encountering an error and can't seem to figure out what's causing it. I've searched for solutions but haven't found one that works yet. I&apo ...

How can I smoothly animate a DIV over a background in both directions?

Unfortunately, the full example I wanted to share is no longer available online. Let me try my best to describe it instead. The idea is to have a continuous looping video as the full-screen background. On top of that, there will be a DIV containing anothe ...

changing a class to JSON format with nlohmann library in C++

Attempting to convert my class to json in visual studio 2017 is resulting in linker errors C2440. Severity Code Description Project File Line Suppression State Error C2440 'initializing': cannot convert from 'ns::person&apos ...

PHP unable to retrieve object from JSON string

{ "travelCoordinates": [{ "longitude": 78.92939102, "latitude": 22.0533782 }, { "longitude": 78.92939102, "latitude": 22.0533782 }], "bookingNumber": 195 } This JSON object is being sent as a string from an ...

Verify the presence of a JSON object within the session storage using JavaScript

I'm currently developing a website where some data is stored within the session. In the initial page, I need to verify if the JSON object already exists in the session. Below is the code snippet that's causing issues: var passedTotal = JSON.par ...

Utilizing numerous copies of a single plugin

I recently integrated a plugin called flip-carousel.js into my website and here is an example of how it looks on the site. Check out the sample implementation Now, I encountered an issue when trying to use multiple instances of the same plugin. When init ...

Vue.js is rendering the chart inaccurately in dc.js

I am currently facing an issue with using dc.js inside a Vue component. My linechart has this filled black area and the brush tool looks different from the normal brush tool. I took this code from my plain JavaScript project. <template> <div> ...

Looking at an HTML string in its natural HTML form

In my AngularJS app, I have autogenerated HTML code that highlights certain texts. The specific line of code responsible for generating this HTML looks like this: var replaced = original.replace(regEx, '<span style="background-color: red;">&apo ...

Utilizing JSON parsing for JSON-LD in JavaScript

Tried parsing a JSON data obtained from json-ld Here's the JSON snippet for reference: { "@context": "http://json-ld.org/contexts/person.jsonld", "@id": "http://dbpedia.org/resource/John_Lennon", "name": "John Lennon", "born": "1940-10-09", ...

An instructional HTML/JS dialogue for a linked page

On my website, there is a link that, when clicked, opens a new tab with a page that I don't control. I want to guide the user on what to do next after they are redirected to this new page ("Now please press the green button on this page"). Ideally, I ...

Storing information on the webpage when it is refreshed

My goal is to maintain the order of the data in the target ordered list even after a page refresh, achieved through jQuery prepend on document ready. Here's the code snippet: // when a refresh event occurs window.onbeforeunload = function(event){ ...

Utilize a JavaScript variable within HTML within the confines of an if statement

On my HTML page, I am dynamically displaying a list of properties and then counting how many are displayed in each div. <script type="text/javascript> var numItems = $('.countdiv').length; </script> The class name for each property ...

Utilizing JavaScript to retrieve data from a self-submitting form

From my database, I am able to create a list of options for users to choose from. Once a selection is made, the values are submitted back to the same page and retrieved using Javascript. Within the same form, there are radio buttons and a multiple selecti ...

Anomalies encountered during the iteration of a table

As I work on building a table by looping through an API array, I've encountered a few obstacles. Here is the code snippet that's causing me trouble -> $html = " <tr class='mt-2'> <td>{$rank}.</td> ...

Enable automatic dropdown menu activation on mobile browsers specifically tailored for Android devices

Is there a way to automatically trigger the opening of a combobox on Android device browsers? Here is the code I have: <!doctype html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> ...

A variety of negative () DOM Selectors

I've been trying to select a specific node using two not clauses, but so far I haven't had any luck. What I'm attempting to achieve is selecting an element whose div contains the string 0008, but it's not 10008 and also does not contain ...

Issues with using hooks in a remote module in Webpack 5 module federation

I am attempting to create a dynamic system at runtime using Module Federation, a feature in webpack 5. Everything seems to be working well, but I encounter a multitude of 'invalid rule of hooks' errors when I add hooks to the 'producer' ...

Show the alert notification just one time every hour in the event that it occurs

I've been struggling to figure out where I'm going wrong with this implementation. Essentially, errors can occur for various reasons, but I only want to display the alert message once every fifteen minutes. For example, if an error occurs at 7:02 ...

Unable to sort nested JSON data in ngTable

I have successfully built an angularjs application using ngTable, however, I am facing an issue with sorting. The JSON structure is nested but the values are appearing correctly in the table. If anyone has a solution to this problem, please let me know. ...

Utilize generic typings to interact with the Array object

I'm facing a challenge in developing an interface that is dependent on another interface. Everything was going smoothly until I reached the Array of Objects. Let me elaborate, I have an 'Entity' that defines how a document is stored in a ...