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.