Home > Enterprise >  What should my API endpoint look like in production?
What should my API endpoint look like in production?

Time:11-14

I have this web app. Frontend is written with VueJS, backend with Django rest framework, and I am using MongoDB with docker volumes.

On the Home page of my web app, Frontend sends a GET request to backend on /api/skills endpoint.

When I handle things locally, everything is fine. I dockerize the frontend, backend, MongoDB and they all talk to each other in the same Docker network.

enter image description here

This is looking nice on local development. The part that does the fetching looks like this.

fetchSkillData: function () {
      const localUrl = "http://0.0.0.0:8000/api/skills";
      axios
        .get(localUrl)
        .then((values) => {
          values.data.forEach((data) => {
            this.technologies.push(data);
            this.hideSpinner();
          });
        })
        .catch(console.error);
      this.hideSpinner();
    }

I am not getting a CORS issue or anything else.

However, on production, I have some issues.

This is the Dockerfile for frontend:

# build stage
FROM node:13-alpine as build-stage
RUN mkdir -p /home/app
COPY ./frontend /home/app

WORKDIR /home/app

RUN npm install
RUN npm install --save ant-design-vue
RUN npm install --save mavon-editor
RUN npm install --save axios
RUN npm install --save raw-loader

RUN npm run build

# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /home/app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

This is the Dockerfile for backend:

FROM python:alpine

ENV MONGO_DB_USERNAME=admin \
    MONGO_DB_PWD=password
    
ENV PYTHONUNBUFFERED 1

RUN mkdir -p /home/app
COPY requirements.txt /home/app

# install requirements
RUN pip3 install -r /home/app/requirements.txt

COPY ./azure_website_backend /home/app
WORKDIR /home/app

EXPOSE 8000

CMD ["python","manage.py","runserver","0.0.0.0:8000","--settings=azure_website_backend.settings"]

And this is the app.yml file for Docker compose:

version: "3"
services:
  vue-frontend:
    image: burakhanaksoy/vue-frontend:1.0
    ports:
      - 8080:8080
  django-backend:
    image: burakhanaksoy/django-backend:1.0
    ports:
      - 8000:8000
  mongodb:
    image: mongo
    ports:
      - 27017:27017
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password
    volumes:
      - mongo-data:/data/db
  mongo-express:
    image: mongo-express
    ports:
      - 8081:8081
    depends_on:
      - mongodb
    environment:
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=password
      - ME_CONFIG_MONGODB_SERVER=mongodb
volumes:
  mongo-data:
    driver: local

When I deploy it on Azure, frontend cannot talk to backend, the same api endpoint has this issue now

enter image description here

I added a CORS middleware on django. So I don't think this issue is related to CORS.

I think the issue stems from me still sending a request to 0.0.0.0. Probably the IP is dynamically changing but I am still sending a request to 0.0.0.0. But I don't know how to fix this. I looked lots and lots of documents and others' questions but I am very novice on deployment so I couldn't figure it out. I appreciate any help.

Also, I know that I shouldn't send to 0.0.0.0 because Azure logs always show a different host port everytime I deploy.

enter image description here


Update

I am trying to integrate nginx with vuejs to make use of proxy_pass.

This is how my dockerfile looks like for Vue

# build stage
FROM node:13-alpine as build-stage
RUN mkdir -p /home/app
COPY . /home/app

WORKDIR /home/app

RUN npm install
RUN npm install --save ant-design-vue
RUN npm install --save mavon-editor
RUN npm install --save axios
RUN npm install --save raw-loader

RUN npm run build

# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /home/app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

And this is nginx.conf:

events { }
http{
  server {
      listen       80;
      server_name  localhost;

      location / {
          root     path/to/vue.js/Project;
          index    index.html index.htm;
          include  /etc/nginx/mime.types;
          proxy_pass http://localhost:8080/;
      }
  }
}

When I build image and run this container. I get 500 Internal Server Error from nginx. This means I integrated nginx but did not configured it properly?

This is what I get

enter image description here


Update 2

Nginx logs the following error on Docker Desktop

/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh

/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh

/docker-entrypoint.sh: Configuration complete; ready for start up

2021/11/13 10:38:20 [error] 32#32: *2 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "0.0.0.0:8080"

2021/11/13 10:38:20 [error] 32#32: *2 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:8080/favicon.ico", host: "0.0.0.0:8080", referrer: "http://0.0.0.0:8080/"

2021/11/13 10:39:11 [error] 32#32: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "0.0.0.0:8080"

2021/11/13 10:39:13 [error] 24#24: *2 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "0.0.0.0:8080"

2021/11/13 10:39:13 [error] 24#24: *2 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:8080/favicon.ico", host: "0.0.0.0:8080", referrer: "http://0.0.0.0:8080/"

2021/11/13 10:40:29 [error] 25#25: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "0.0.0.0:8080"

2021/11/13 10:40:29 [error] 25#25: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:8080/favicon.ico", host: "0.0.0.0:8080", referrer: "http://0.0.0.0:8080/"

CodePudding user response:

Try this:

fetchSkillData: function () {
    const localUrl = "/api/skills";
    axios
        .get(localUrl)
        .then((values) => {
          values.data.forEach((data) => {
            this.technologies.push(data);
            this.hideSpinner();
          });
        })
        .catch(console.error);
      this.hideSpinner();
    }

Or this:

async fetchSkillData(){
   try {
     const resp = await axios.get('/api/skills');
     console.log(resp.data);
   } catch (err) {
     // Handle Error Here
     console.error(err);
   }
}

CodePudding user response:

If you deploy on Azure you will have another hostname then when you deploy locally. Appearently you port to 0.0.0.0 locally, but when you deploy a docker container on Azure it will not do anything unless you also configured a Virtual Machine or AKS. That depends on your setup.

Virtual machines

Your Virtual Machine will have a custom hostname which will be the same as your Virtual Machine.

AKS

If you configured AKS you must create a deployment where you link to your docker container to spin up some replica's. More about deployments on K8s docs. Once you did a deployment you need a service to expose your deployment outside the cluster. You can use a variety of services, but usually yoiu have to configure ClusterIP and Ingress. The hostname of your deployment equals themetdata.name:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-custom-host-name

Vue app

To use environment variables with Vue3 you have to pass those before you build your front-end. Those environment variables will be interpolated in your code via: process.env.VUE_APP_BACKEND_BASE_URL. For Vue3 you must prefix environment variables with VUE_APP_ or use a .env file. So add the following env before you run your build script in the pipeline:

 VUE_APP_BACKEND_BASE_URL=http://[BACKEND_HOST]:8000 npm run build

Docker compose

In docker-compose you have to set the env var as well and rebuild the application using docker-compose up or docker compose up. Please note the hostname in docker compose is the name of your service.

version: "3.8"
services:
  vue-frontend:
    image: burakhanaksoy/vue-frontend:1.0
    ports:
      - 8080:8080
    environment:
      - VUE_APP_BACKEND_BASE_URL=django-backend:8000

  django-backend:
    image: burakhanaksoy/django-backend:1.0
    ports:
      - 8000:8000
  mongodb:
    image: mongo
    ports:
      - 27017:27017
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password
    volumes:
      - mongo-data:/data/db
  mongo-express:
    image: mongo-express
    ports:
      - 8081:8081
    depends_on:
      - mongodb
    environment:
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=password
      - ME_CONFIG_MONGODB_SERVER=mongodb
volumes:
  mongo-data:
    driver: local
  • Related