Home > Software engineering >  Failed to fetch with Docker, MySQL, Express and TypeScript
Failed to fetch with Docker, MySQL, Express and TypeScript

Time:10-09

I tried to create a todo-app with Node.js, TypeScript, MySQL. This app works well. There is no issue.

However, when I tried to have this app on Docker Container, I have the following error.

Failed to load resource: net::ERR_NAME_NOT_RESOLVED
TypeError: Failed to fetch
    at getTodos (ListTodo.tsx:16)
    at ListTodo.tsx:25
    at invokePassiveEffectCreate (react-dom.development.js:23487)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at flushPassiveEffectsImpl (react-dom.development.js:23574)
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at flushPassiveEffects (react-dom.development.js:23447)
    at react-dom.development.js:23324
    at workLoop (scheduler.development.js:417)
    at flushWork (scheduler.development.js:390)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:157)

I failed to fetch data.


The backend code is:

//index.ts
import express from 'express';
import cors from 'cors';
import { Express, Request, Response } from 'express';
import { createPool, RowDataPacket } from 'mysql2';

const pool = createPool({
  host: 'mysqldb',
  port: 3306,
  user: 'root',
  password: 'pass123',
  database: 'todo',
});

const app: Express = express();
app.use(cors());
app.use(express.json());

app.get("/todos", async (req: Request, res: Response) => {
  try{
    const resp = await pool.promise().query<RowDataPacket[]>(
      'SELECT * FROM todo'
    );
    res.json(resp[0]);
  } catch (error) {
    throw error;
  }
});

app.listen(5000);

The frontend code is:

import React, { useState, useEffect } from 'react';

export const ListTodo = () => {
  const [todos, setTodos] = useState([]);
  const getTodos = async () => {
    try {
      //fetch data
      const response = await fetch('http://api-prod:5000/todos');
      const jsondata = await response.json();
      setTodos(jsondata);
    } catch (err) {
      console.log(err);
    }
  };
  useEffect(() => {
    getTodos()
  }, []);

  return (
    //list data
  );
};

docker-compose file is:

//docker-compose.yml
version: "3"

services:
  mysqldb:
    platform: linux/x86_64
    image: mysql:8.0
    hostname: mysqldb
    environment:
      - MYSQL_ROOT_PASSWORD=pass123
      - MYSQL_DATABASE=todo
    ports:
      - 3306:3306
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - shared-network
    volumes:
      - db-config:/etc/mysql
      - db-data:/var/lib/mysql
      - ./db/backup/files:/data_backup/data

  nginx:
    image: nginx
    container_name: nginx_prod
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    ports:
      - 80:80
    depends_on:
      api-prod:
        condition: service_healthy
      app-prod:
        condition: service_started
    networks:
      - shared-network

  api-prod:
    container_name: server_api_prod
    build:
      context: server
      dockerfile: Dockerfile
    hostname: api-prod
    depends_on:
      - mysqldb
    networks:
      - shared-network
    ports:
      - 5000:5000
    restart:
      unless-stopped
    healthcheck:
      test: ["CMD", "curl", "http://api-prod:5000"]
      interval: 5s
      timeout: 3s
      retries: 6

  app-prod:
    container_name: client_app_prod
    build:
      context: client
      dockerfile: Dockerfile
    hostname: app-prod
    ports:
      - 3000:3000
    networks:
      - shared-network
    restart:
      unless-stopped

networks:
  shared-network:

volumes:
  db-config:
  db-data:

Why I fail to fetch data? I think I have a correct database connection(host:mysqldb, port:3306).

CodePudding user response:

Your React app runs in your browser, where you can't use the Docker hostnames. Those are only available on the Docker bridge network.

So your React app can't resolve the name api-prod. You need to use a name that can be resolved from the browser. If you run the app locally, you can use localhost. If you want to deploy it and use it from other computers, you need to use a name that can be resolved from those computers.

But for running locally

fetch('http://localhost:5000/todos')

should do the trick.

  • Related