Andres Urdaneta
Andres Urdaneta

Reputation: 441

Trouble Deploying Angular/Express App in Heroku frontend cannot hit the API endpoint

Currently in development it works just fine... localhost:4200 for the front-end and localhost:8080 for the back-end

However, I just deployed it and the front-end get displayed, but isn't getting the data from the API because in my app.service.ts I'm doing the following:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  private apiUrl = 'http://localhost:8080/api'

  constructor(private http: HttpClient) { }

  public getNews() {
    return this.http.get(`${this.apiUrl}/countries`)
  }
}

As you can see, I'm hardcoding the localhost:8080 and it works fine in development, but when it comes to production Heroku does not assign me the port 8080, it assigns me another one.

That being said... How can I tweak this in order to read the port Heroku gives me?

This is my app.js file

const express = require('express');
const app = express();
const scrapper = require('./backend/scrapper')

// Create link to Angular build directory
var distDir = __dirname + "/dist/covid19";
app.use(express.static(distDir));

app.use((req, res, next) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader(
        "Access-Control-Allow-Headers",
        "Origin, X-Requested-With, Content-Type, Accept, Authorization"
    );
    res.setHeader(
        "Access-Control-Allow-Methods",
        "GET, POST, PATCH, PUT, DELETE, OPTIONS"
    );
    next();
});

app.use("/api/countries", async (req, res, next) => {
    const data = await scrapper.getCountries()
    res.status(200).json(data)
})

const port = process.env.PORT || 8080;
app.listen(port, () => {
    console.log(`API listening on port ${port}...`);
});

module.exports = app;

As you can see I'm declaring my port to be process.env.PORT || 8080, but this is for the backend... How can achieve this but in my API call in the service.ts file?

Upvotes: 0

Views: 656

Answers (3)

dezmasterflex
dezmasterflex

Reputation: 17

You have to refer to the production variables when deploying your app. I like using the isDevMode function included in the '@angular/core' package.

import { isDevMode } from '@angular/core';

setUrl(){
 if(isDevMode() == true){
 //in development mode
 api_url = "localhost:4200"
 }else{
 api_url = "heroku.app_url.app"
 }
}

This function lets you know which mode the app is running in, so you can use that to switch between connection strings.

Upvotes: 0

Andres Urdaneta
Andres Urdaneta

Reputation: 441

You guys pointed me in the right direction, but to be precise:

I noticed that in Angular you get a environments folder with two files 1. environment.ts and environment.prod.ts.

I just had to make sure to use to point to the URL that Heroku gave me for my app after deploying yourappname.herokuapp.com, by doing the following in my environments.prod.ts (Which is the one that Heroku is gonna look for)

export const environment = {
  production: true,
  apiUrl: "https://yourappname.herokuapp.com/api"
};

And in my api.service.ts I ended up with the following code:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment'

const API_URL = environment.apiUrl;

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private http: HttpClient) { }

  public getNews() {
    return this.http.get(API_URL + '/countries')
  }
}

Upvotes: 2

Tin Nguyen
Tin Nguyen

Reputation: 5330

When you deploy a web server on Heroku you bind to the $PORT Heroku tells you to bind to.

When you visit your deployed app you don't specify a port. You just connect to yourappname.heroku.com. The DNS automatically translates it into ipaddress:port.

So on your frontend you just point to yourappname.heroku.com instead of ipaddress:port.

Upvotes: 1

Related Questions