How to pass runtime environment variables to client side in NuxtJS SSR application - vuejs2

My NuxtJS applications makes HTTP request to a backend API. I am using nuxtjs/axios pluging to make these requests. I have configured base URL for API in nuxt.config.js like below
axios: {
baseURL: process.env.BASE_URL,
},
In Local, I have a .env like below
BASE_URL=http://localhost:8080
On AWS ECS Container, I have declared environment variable with
Key: BASE_URL and Value: https://example.com
On running the application following happens
When application is server-side rendered, base URL for API is resolved correctly e.g https://example.com/previews
When application is client-side rendered, base URL for API is not resolved to https://example.com but rather to the same IP address that my web application is accessible on.
So, what I understand might be happening is, that the process.env.BASE_URL is not getting passed from the server-side(NodeJS server) to client-side(Web Browser). Hence it is falling back to the application's IP address.
Any idea why such a behavior and how to pass the environment variable to client-side as well? Or what might be causing this.
Thanks.

Related

React Front-end connecting to Java Backend on Gitpod HTTPS

I have a project which I have dockerised here: https://github.com/redis-projects/redis-movies/tree/gitpod
I am in the process of trying to get it to work correctly on GitPod, however I am having issues with the frontend react app hitting the backend java service. The react app is running in my local browser so I am confused by which network settings I should use and how to correctly configure.
The docker-compose file when used locally can simply use localhost:8080 to interact with the backend services, but GitPod generates a unique domain over HTTPS. Currently this causes the issues:
Mixed Content: The page at '<URL>' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint '<URL>'. This request has been blocked; the content must be served over HTTPS.
This is self-explanatory, I cant make HTTP requests when the site is loaded via HTTPS. & even if I could, its pointing # localhost so the service wont resolve.
How can I setup my docker-compose + gitpod configuration to correctly configure the React URL
Currently use env vars:
REACT_APP_MOVIE_SERVICE_HOST=localhost
REACT_APP_MOVIE_SERVICE_PORT=8080
and this simply builds a url like so (apiConfig.js): http://${process.env.REACT_APP_MOVIE_SERVICE_HOST}:${process.env.REACT_APP_MOVIE_SERVICE_PORT}
Assuming that the backend services are exposed via a public endpoint, I will need to handle any CORs issues since these services are no longer 'local'?

How to bypass router for certain URLs with Vue Router?

I'm using Vue Router with Vue 3 in a web application I'm working on, and have a 'catch all' route defined as the last route:
{
path: "/:catchAll(.*)*",
component: () => import("pages/Error404.vue")
},
This is picking up everything, though, including calls to the /api/ back end (although not via Ajax), and even things like '/test.csv', which is a link to a CSV file in the root directory.
How can I bypass the router for certain URLs, allowing them to be treated as regular requests?
Incidentally, I don't know whether this is relevant, but the application in question is a PWA built using Quasar. When I make the call to e.g '/test.csv', I see a request for 'service-worker.js' with a 304 response code in my nginx access log, confirming that the request is being handled by the router rather than nginx.

Heroku adding 'undefined' to BASE_URL environment variable

attempting to deploy a vuejs, express app to heroku. The app displays, but cannot access the api, because heroku seems to add 'undefined' in the middle of the base_url. Everything works locally as expected.
Here is my heroku config var:
BASE_URL: https://goore-todos.herokuapp.com/
Here is the Vuejs component api request:
fetchTodo () {
let uri = process.env.BASE_URL + '/api/all';
axios.get(uri).then((response) => {
this.todos = response.data;
});
},
As mentioned, this works locally.
the console shows the following error:
VM71:1 GET https://goore-todos.herokuapp.com/undefined/api/all 404 (Not Found)
and the view is empty.
requests to https://goore-todos.herokuapp.com/api/ via Postman work as expected.
In this case it looks like process.env.BASE_URL is undefined. As it is undefined, the url you're trying to access is considered to be relative. That means it uses your current domain and appends the path to it.
If your frontend and backend are running on the same domain there is no reason to try to pass the API url as a variable as you can just use relative URLs.
If you want to access the URL via an environment variable it is a bit trickier with a frontend app. The Vue app is running on the user's browser, not on your server so you can't directly access it.
I had this problem and had to go through and hard code all of my URLs with the heroku URL. I tried resetting the config variables in Heroku which had an extra slash at the end, but in the end hard-coding each API call was the only thing that fixed it.

Dynamically change API route for SPA

I am currently building a SPA app using Vue.js and webpack to do our bundling. The backend API is built with .Net Core. When running locally, the Vue app is hitting localhost on the backend. I need to be able to change the route of the API dynamically based on the environment. Is there a way to do this without having to do a big switch statement that considers the current url? A requirement is that we are not allowed to change the webpack bundle for different environments, in other words, once it is bundled, it has to stay bundled. I have tried to pass static config files through to the bundle and dynamically change them based on the environment, but unfortunately that does not work, as it hits the values that were originally in them.
webpack dev server has a proxy capability. You could use this to proxy to your locally running backend when developing.
https://webpack.js.org/configuration/dev-server/#devserver-proxy
e.g. you can point anything from '/api' to 'localhost:8888/api' with the config.
Is your app the backend running on the same url when deployed? If not, you'll likely need a reverse proxy to pass along the requests to the backend.
You can use an axios interceptor so you only have that switch in one place:
axios.interceptors.request.use(config => {
// check location.host name and append the backend url you want
});
see https://github.com/axios/axios#interceptors
However, this is a little dangerous as the URLs in your switch statement will be strings, and therefore all of your environment URLs can be pulled out of your code even if minified/concatenated.
Another option is to add some sort of endpoint to the server your client side code is hosted, and when you start your app, query for that configuration.

Different ports for frontend and backend. How to make a request?

Using Angular-CLI as a frontend. 4200 port
Using Express as a backend. 8080 port
Directories look like:
Application
- backend
- ...Express architecture
- frontend
-...Angular2 architecture
So I'm running two projects, two commanders, one for frontent, second one for backend. node app.js for backend (8080), ng serve for frontent (4200).
Let's assume that I have a layer in backend which returns some string.
app.get('/hello', function(req, res) {
res.send("Hello!");
}
How can I make a request from frontend to backend and get that string? I don't want to know how exactly should I use Angular2 because that's not the point. I'm asking, what technology should I use to be able connect these two (frontent and backend) sides on different ports. If I just run them and make a request from frontend, I'll get an error because it can't find /hello url.
Your request to /hello means an absolute path inside the application running the angular application, so the request goes to http://localhost:4200/hello. Your angular application just doesn't know about the express application you want to target.
absolute urls
If you want to access the hello route on the other (express) application, you need to explicitly specify this by referencing http://localhost:8080/hello.
cors
Doing it this way, the correct application is targeted, but you will likely run into CORS issues, because the browser will prevent the javascript code obtained from localhost:4200 to access a server at localhost:8080. This is a security feature of your browser. So if you want to allow the code at 4200 to access the backend at 8080 your backend can whitelist this so called origin. For details see http://enable-cors.org/ and a corresponding express middleware you could use to support cors in your backend (https://www.npmjs.com/package/cors).
Using this approach has two downsides in my opinion. First, you need a way to tell your frontend under which absolute url it can reach the backend. This must be configurable because you need different urls for dev, staging and production. You then also need a way to manage all your whitelisted urls because the frontend in production will have a different url than when running the frontend in development. This can get pretty cumbersome to handle.
proxying your backend
A better approach in my opinion is to handle this in your infrastructure by proxying the backend in your frontend application. With proxying you basically tell your frontend server that all requests to some url should be passed through to another application. In your case this could probably mean, that for example you configure a proxy for the path /api/ to proxy the application on localhost:8080. The server then doesn't try to find a url like /api/hello on your frontend application but forwards your request to localhost:8080/hello. In your angular application you then don't need to care about the url of your backend and you can then always do a request to a url like /api/some-express-route.
For this to work you need to configure your angular dev server to proxy the requests. For details on how to do this, please see the docs at https://angular.io/guide/build#proxying-to-a-backend-server. When going to production, you can do this by configuring your web server, e.g. nginx to proxy the requests.