Dexter
Dexter

Reputation: 528

How to import .json config to environment.ts and consume api using Angular?

I want to import a Json file which is in assets folder where I have below urls:

config.json:

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

So instead of hard coding the URL, I want to import from Json file, but I am not sure how to do that exactly.

Any suggestions or scenarios would be appreciated, below are my issues:

1. How to import Json file to environment.ts and from there I will have a service which consumes the api

2. If I import the file, it needs to be the same for prod and loc dev also

what I want :

I have a config file where it contains some URL's in .json file stored in asset folder now instead of loading environments.prod or .ts, I want to load my Json file config and basing on that I want to run my application

what I did:

Below is my Json file which I placed in asset folder

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

ConfigServiceService.ts for storing config file

public _config: Object;

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

After this, I create 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 not able to get the Json data and if I am putting the logic which is there is ngOnInit in ServiceProviderService.ts file if I put it in constructor then I am getting undefined.

Note : here if there are more than once url then each url is distributed to various seperate service file suppose base1 url for 1 service file ans base2 url for another file how can I achieve that

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

in app.component.ts im getting undefined

enter image description here

Upvotes: 8

Views: 15351

Answers (8)

Mike Gledhill
Mike Gledhill

Reputation: 29213

I'm not sure if this is the best solution, but here's what I did (by cut'n'pasting what was already in the default Angular project). I had the same goal: I wanted an "API URL" to be available, depending on which environment (Debug or Production) we were using.

First, I added an extra config setting to the two existing .ts files:

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

..so now, each of the files looked something like this:

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

The main.ts file already has code to read in the environment object, and it uses the environment.production value, so I just added a bit of code to this file to do the same with the environment.apiUrl value:

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));

With this in place, I can access this new "API_URL" value in my components.

For example:

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);
  }
}

When I open this page, I can see my URL shown in the Output window.

FetchDataComponent, URL: http://localhost:53104

Is this solution okay ? It seems a lot simpler (with almost no code) than the other solutions.

Actually, an even simpler solution is to not use a "API_URL" provider, and just stick this in your components:

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

..then just access the value using:

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

Job done !

Upvotes: 0

Yakir Tsuberi
Yakir Tsuberi

Reputation: 1513

If you want to import json file

  1. Add config.json to the assets directory.
  2. Edit typings.d.ts file:
    declare module "*.json" {
        const value: any;
        export default value;
    }
  1. Add path of typings.d.ts to "typeRoots" in tsconfig.json, for example:
"typeRoots": [
      "node_modules/@types", "./src/typings.d.ts"
],
  1. Import config.json in environment file:
import * as config from '../assets/config.json';

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

That's all, good luck!

Upvotes: 0

Vega
Vega

Reputation: 28738

Since you have static strings in a JSON file, which is already saved in /assets folder and it's not on the server, you don't need to use http.get.
We use http protocol to get data from JSON files from the server/backend only, not from the client side folders.
You just need to import the JSON file wherever you need (even in environment.ts), as you would do with DTOs. Use Typescript's ES6 import statement combined with export in 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 anywhere (components, directives, services, classes, interfaces, etc ...)

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

....

this.url1 = URLS.url1;

//or

let url1 = URL.url1;

Now this.url1 can be used in any api call inside 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's it

Upvotes: 16

Muhammed Albarmavi
Muhammed Albarmavi

Reputation: 24472

You can use required 🤔 to read a json file from assets

/assets/urls.json 📄

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

env.ts

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

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

env.prod.ts

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

🚨 you need to install npm i @types/node and update tsconfig.app.json like this

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

Upvotes: 1

Doug S.
Doug S.

Reputation: 682

So, I would create a node script called populatedDynamicUrls.js that can read those values IN from the json file, and write those values OUT to the corresponding environment.ts file for that specific environment. THEN your angular build command would look like this: node populateDynamicUrls.js && ng run build, and your angular serve command would look like this: node populateDynamicUrls.js && ng run serve

Upvotes: 0

JayK
JayK

Reputation: 73

    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",
        } 
      }

you can import the baseUrl property in the asset folder to your service file and execute as I mentioned above.

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

Please find the url for detailed explanation of environment variables in angular

Upvotes: 0

Hien Nguyen
Hien Nguyen

Reputation: 18973

You can create a service to read Json file using HttpClient

export class SettingService  {

  constructor(private http: HttpClient) {

  }

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

You should save 3 url to session storage or localstorage instead of enviroment.ts incase you refresh page

Refer Angular: Is it possible to read a json file after building

Upvotes: 0

Idris Rampurawala
Idris Rampurawala

Reputation: 65

You can create constants for all these urls in environment file. I do not see a scenario in your case to put it in a separate json file. For prod, you can use the same environment file by changing default configurations property in angular.json

Upvotes: 0

Related Questions