Question:
How to use Axios in the dev environment?

Query: How to use Axios in the dev environment inside the docker network AND from the docker host?


Problem

I'm building a web application, that's supposed to run on different docker containers:


version: "3.8"

services:

  backend:

    build: ./backend

    container_name: app-be

    ports:

      - 8000:8000

    volumes:

      - ./backend:/app


  frontend:

    build: ./frontend

    container_name: app-fe

    ports:

      - 5173:5173

    volumes:

      - ./frontend:/app


  test:

    build: ./test

    container_name: app-e2e

    command: npx cypress run -b firefox

    environment:

      - CYPRESS_baseUrl=http://frontend:5173

    tty: true

    volumes:

      - ./test:/app


The frontend is a Vuejs app, and I am trying to access the backend via Axios; when starting up everything, the app also gets tested by Cypress. But I also want to see my changes locally; which is creating my problem:


In order to access the backend from the host, Axios would need to use http://localhost:8000 as the address for the backend, but then, of course, the Cypress tests would fail; for those, Axios would need to access http://backend:8000 which again is unknown to the host. 


However, I want both cases covered.


export default {

  data() {

    return { msg: '' };

  },

  methods: {

    getMessage() {

      axios.get('http://backend:8000/') // <-- change to localhost when running in browser

           .then((res) => { this.msg = res.data; })

           .catch((error) => { console.error(error);});

    },

  },

  created() {

    this.getMessage();

  },

};


Coming from backend development, I would usually solve something like this with different environment files that get sourced according to the environment - but in this case, Axios runs as JavaScript on the client, so this cannot be solved on the server side, as it is the same server used. One could change this, of course - have two frontend instances running - one for the cypress tests and another for local development, and start them up with different environment variables, but that feels somewhat dirty.


Another workaround is adding the line 127.0.0.1 backend to the systems /etc/hosts, but I don't feel good with this solution either; for me, one main benefit of using docker is to enable others to just download the project and run it without the need of installing anything on their local machine. Needing root rights to change an essential system config somehow defeats that idea.


So my question: Is there a better way of solving this problem that I am not seeing? Or are these really the only two options available?


Solution

So I found a better solution that I am happy with, thanks to the >comment by David Maze, but it involved some more work.


After adding the nginx proxy >as explained, i.e.

  • adding to docker-compose:


proxy:

    build: ./proxy

    container_name: app-prx

    ports:

        - 80:80


  • introducing new Dockerfile in ./proxy/:


FROM nginx:1.25.2-alpine

COPY default.conf /etc/nginx/conf.d


  • introducing new config file for nginx in ./proxy/default.conf:

 

  server {

        listen 80;

        server_name localhost;

        location / {

            proxy_pass http://frontend:5173/;

        }

        location /api/ {

            proxy_pass http://backend:8000/;

        }

    }


and then fixing Cypress to visit http://proxy/ and fixing the frontend calls to the backend from http://backend:8000/ to /api/, the project would actually show the correct result in the local browser. However, my cypress tests where failing with a strange message:


An invalid or illegal string was specified


Turns out, that when looking into the console locally you get a more helpful message:


  Firefox can't establish a connection to the server at ws://localhost/.

    Uncaught (in promise) DOMException: An invalid or illegal string was specified

        setupWebSocet client.ts: 77

        fallback      client.ts: 42

    (...)


I don't know why this is happening, but for some reason when adding an Nginx, vite needs to have a websocket specified in the vite.config.js:


export default defineConfig({

    plugins: [

        vue(),

    ],

    (...)

    server: {

        hmr: {

            port: 5173

            host: "localhost",

            protocol: "ws",

        },

    },

})


NB: It is important to add all three components - I first left out the port, which led to the same error as before (and therefore took me even longer to figure this out). Depending on how you start your frontend, this might lead to a new error:

  

Port 5173 is in use, trying another one.

    error when starting dev server:

    Error [ERR_SERVER_ALREADY_LISTEN]: Listen method has been called more than once without closing.


In this case make sure, that you are explicitly starting the frontend with a port specified. In my case, I am doing this at the end of my Dockerfile for my frontend:


  CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]


For me, this is a far superior setup compared to the other two I presented above for 4 reasons:


  1. It solves my initial problem, i.e. it's runnable both inside docker and from the host, without needing to change the host.

  2. It also simplifies all the routes in the front (before I created an instance of Axios as a helper to set the base URL: 'http://backend:8000' and export it to all my components - no need for that anymore).

  3. You'd probably want an nginx anyways as soon as you go into production.

  4. Given 3, you're not spawning "useless" docker containers that are just copies of other containers with different environment settings just to satisfy client-side Browser scripts.


Suggested blog

>How to get the date and time and display it in a defineProps in Vuejs?

>Why logged user object is all strings in Vuejs and Laravel 10?

>What is meant by progressive framework?

>How can I replace this.$parent in composition API in Vuejs?

>How do I fix an invalid route component in the new VueJs Project?

>How to get all the rows selected in Vuejs?

>How to set up a dynamic grid based on flex or grid in Vuejs?

>Create a project using Vue.js: Beginners Guide

>Authentication with Vue 3 and Firebase

>Plugins and Presets for Vuejs project

>Create a Vue.js application with CLI Services

>Create a project using Vue.js: Beginners Guide

>Create Vue.js application API


Nisha Patel

Nisha Patel

Submit
0 Answers