티스토리 뷰

백엔드의 개발 서버 역할을 해줄 api

cd api

npm install

 

서버열기

npm run dev

 

프론트엔드의 개발 서버 역할을 해줄 my-app

cd my-app

npm install

 

서버 열기

npm start

npm run dev 역할 과 npm run start 역할

npm run dev 명령어는 api 프로젝트의 개발 서버를 실행한다.

이 서버는 백엔드 개발에 사용된다.

백엔드 개발 서버는 API 엔드포인트를 제공하고, 데이터베이스와 연동하여 데이터를 응답한다.

 

반면에, npm start 명령어는 my-app 프로젝트의 개발 서버를 실행한다.

이 서버는 프론트엔드 개발에 사용된다.

프론트엔드 개발 서버는 사용자 인터페이스(UI)를 제공하고, 백엔드 API 엔드포인트와 통신하여 데이터를 가져온다.

 

 

api 프로젝트와 my-app 프로젝트는 서로 다른 프로젝트이지만,

백엔드 API 서버와 프론트엔드 개발 서버는 서로 연결되어 있다.

따라서, my-app 프로젝트에서 백엔드 API 서버로 요청을 보내려면, "proxy" 옵션을 설정해야 한다.

 

하지만, "proxy" 옵션은 my-app 프로젝트에서만 작동하기 때문에,

api 프로젝트에서도 "proxy" 옵션을 설정해야 my-app 프로젝트에서 api 프로젝트의 백엔드 API 서버에 대한 요청을 보낼 수 있다.

 

webpack dev server의 proxy 기능을 사용해 우회하여 응답을 받아오기

app.js , my-app 폴더에 package.json 안에 넣었다.

....
},
	"proxy" : "http://localhost:3080"
}

BookService.js

도메인을 제거해주니 CORS 에러 해결

export const getAllBooks = async () => {

    const response = await fetch('/api/books');
    return await response.json();
}

export const createBook = async (data) => {
    const response = await fetch('/api/book', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({book: data})
      })
    return await response.json();
}

+api2 폴더

여러 개의 도메인에서 응답을 받아와야 하는 경우있다.

http-proxy-middleware의 proxy 기능을 사용하여 proxy를 유연히 설정해 2개의 도메인에서 모두 응답을 받아와야한다.

백엔드의 개발 서버 역할을 해줄 api2

cd api2

npm install

 

서버열기

npm run dev

 

package.json proxy 기능을 지운다.

npm install http-proxy-middleware --save 라이브러리 설치

 

React App의 src 파일 안에서 setupProxy.js 파일을 생성한후 코드 작성

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(
        "/api",
        createProxyMiddleware({
            target: "http://localhost:3080",
            changeOrigin: true,
        })
    ),
    app.use(
        "/api2",
        createProxyMiddleware({
            target: "http://localhost:3070",
            changeOrigin: true,
        })
    );
};

api2.js

const express = require('express');
const path = require('path');
const app = express(),
      bodyParser = require("body-parser");
      port = 3070;
//bodyParser를 사용하여 HTTP request body를 파싱하고, 포트 번호를 정의

const todos = [{
  todo: "산책하기",
  category: "운동",
  isComplete: true
  }];
//todos라는 배열을 선언하여 API가 반환할 데이터를 담고 있다.

app.use(bodyParser.json());
//bodyParser.json()은 HTTP 요청의 본문을 JSON 형식으로 파싱하도록 하는 미들웨어
app.use(express.static(path.join(__dirname, '../my-app/build')));
//정적 파일을 제공하는 미들웨어인 express.static()을 등록
//이 미들웨어는 클라이언트에서 정적 파일을 요청할 때마다 서버에서 파일을 찾아서 전달

app.get('/api2/todos', (req, res) => {
  console.log('api/todos called!')
  res.json(todos);
});

app.post('/api2/todo', (req, res) => {
  console.log('Adding user:::::', req.body.todo);
  todos.push(req.body.todo);
  res.json("todo added!");
});

app.get('/', (req,res) => {
  res.send(`<h1>API Running on the port ${port}</h1>`);
});

app.listen(port, () => {
    console.log(`Server listening on the port::${port}`);
});
BookS

BookService.js

api2 fetch를 추가 시켜줬다.

export const getAllTodos = async () => {

    const response = await fetch('/api2/todos');
    return await response.json();
}

export const createTodos = async (data) => {
    const response = await fetch('/api2/todo', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({todo: data})
      })
    return await response.json();
}

CreateTodo.js

 

import React from 'react';


const CreateTodo = ({ onChangeForm, handleSubmit }) => {


    return(
        <div className="form-wrapper">
            <div className="form">
                <form>
                    <div className="input-group">
                        <label>todo</label>
                        <input 
                            type="text" 
                            onChange={(e) => onChangeForm(e)} 
                            name="todo" 
                            placeholder="todo" 
                        />
                    </div>
                    <div className="input-group">
                        <label>category</label>
                        <input 
                            type="text" 
                            onChange={(e) => onChangeForm(e)} 
                            name="category" 
                            placeholder="category" 
                        />
                    </div>
                    <div className="input-group">
                        <label>isComplete</label>
                        <input 
                            type="text" 
                            onChange={(e) => onChangeForm(e)} 
                            name="isComplete"
                            placeholder="isComplete" 
                        />
                    </div>
                    <button 
                        className="submit-button"
                        onClick= {() => handleSubmit()}
                    >Submit
                    </button>
                </form>
            </div>
        </div>
    )
}

export default CreateTodo;

 

DisplayBoard.js

import React from 'react'

const DisplayBoard = ({numberOfBooks, getAllBook, getAllTodo, numberOfTodos}) => {
    
    return(
        <div className="display-wrapper">
            <div className="display-box">
                <div className="display-board">
                    <h4>생성된 수</h4>
                    <div className="number">
                    {numberOfBooks}
                    </div>
                </div>
                <div className="display-board">
                    <h4>생성된 todo 수</h4>
                    <div className="number">
                    {numberOfTodos}
                    </div>
                </div>
                <div className="get-button">
                    <button onClick={() => getAllBook()}>Get all Books</button>
                    <button onClick={() => getAllTodo()}>Get all todos</button>
                </div>
            </div>
        </div>
    )
}

export default DisplayBoard;

TodoTable.js

import React from 'react'

const TodoTable = ({todos}) => {

    if (todos.length === 0) return null;

    return(
        <div className="table-wrapper">
            <div className="table-box">
                <h2>My Todos</h2>
                <div className="table-scroll">
                    <table>
                        <thead>
                        <tr>
                            <th>Id</th>
                            <th>todo</th>
                            <th>Category</th>
                            <th>isComplete</th>
                        </tr>
                        </thead>
                        <tbody>
                            {todos.map((todo,index) => {
                                return (
                                    <tr key = {index} className={index%2 === 0?'odd':'even'}>
                                        <td>{index + 1}</td>
                                        <td>{todo.todo}</td>
                                        <td>{todo.category}</td>
                                        <td>{todo.isComplete}</td>
                                    </tr>
                                )
                            })}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    )
}

export default TodoTable;

 

App.js

import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import BookTable from './components/BookTable';
import TodoTable from './components/TodoTable';
import DisplayBoard from './components/DisplayBoard';
import CreateBook from './components/CreateBook';
import CreateTodo from './components/CreateTodo';
import { getAllBooks, createBook, createTodos, getAllTodos} from './services/BookService';
import Footer from './components/Footer';


function App () {
  const [bookShelf, setBookShelf] = useState({});
  const [myTodo, setMyTodo] = useState({});
  const [books, setBooks] = useState([]);
  const [numberOfBooks, setNumberBooks] = useState(0);
  const [todos, setTodos] = useState([]);
  const [numberOfTodos, setNumberOfTodos] = useState(0);

  const handleSubmit = () => {
      createBook(bookShelf)
        .then(() => {
          setNumberBooks(numberOfBooks+1);
      });
  }

  const handleTodoSubmit = () => {
    createTodos(myTodo)
      .then(() => {
        setNumberOfTodos(numberOfTodos+1);
    });
}

  const getAllBook = () => {
    getAllBooks()
      .then(data => {
        setBooks(data);
        setNumberBooks(data.length);
      });
  }

  const getAllTodo = () => {
    getAllTodos()
      .then(data => {
        console.log(data)
        setTodos(data);
        setNumberOfTodos(data.length);
      });
  }


  const handleOnChangeForm = (e) => {
      let inputData = bookShelf;
      if (e.target.name === 'book') {
        bookShelf.book = e.target.value;
      } else if (e.target.name === 'category') {
        bookShelf.category = e.target.value;
      } else if (e.target.name === 'author') {
        bookShelf.author = e.target.value;
      }
      setBookShelf(inputData);
  }

  const handleOnChangeTodoForm = (e) => {
    let inputData = myTodo;
    if (e.target.name === 'todo') {
      myTodo.todo = e.target.value;
    } else if (e.target.name === 'category') {
      myTodo.category = e.target.value;
    } else if (e.target.name === 'isComplete') {
      myTodo.isComplete = e.target.value;
    }
    setMyTodo(inputData);
}

  

  
  return (
    <div className="main-wrapper">
      <div className="main">
        <Header />
        <div className='handel_form'>
        <CreateBook 
          bookShelf={bookShelf}
          onChangeForm={handleOnChangeForm}
          handleSubmit={handleSubmit}
        />
        <CreateTodo 
        myTodo={myTodo}
        onChangeForm={handleOnChangeTodoForm}
        handleSubmit={handleTodoSubmit}
        />
        </div>
        <DisplayBoard 
          numberOfBooks={numberOfBooks} 
          getAllBook={getAllBook}
          getAllTodo={getAllTodo} 
          numberOfTodos={numberOfTodos}
        />
        <BookTable books={books} />
        <TodoTable todos={todos} />
        <Footer />
      </div>
    </div>
  );
}

export default App;

브라우저 -> 리액트 앱 -> 프록시 서버 -> API 서버

리액트 앱에서 API 서버에 데이터를 요청하는 코드

리액트 앱에서 프록시 서버로 요청 3000

프록시 서버는 API서버로 전달 8000

API 서버(localhost:8000) 에서 프록시 서버로 응답 OK(8000)

프록시 서버에서 리액트 에서 응답전달(3000)

 

API 주소 2개 이상

 

1개면 -> package.json 그냥 실행

2개면 -> 유연하게 설정할 필요성이 있다.(2개이상의 서비스를 할수 있다.)

 

CRA로 app을 만들면

package.json에 proxy 설정하는게 어려워짐

미들웨어 사용해 유연하게 프록시 설정을 써서 API주소를 잘 받아온다.

 

 

'codestates > section4' 카테고리의 다른 글

Unit12 - Coz’ Mini Hackathon  (0) 2023.04.07
Unit11 - [자료구조/알고리즘]  (0) 2023.04.05
과제1. Github Action 실습  (0) 2023.04.03
Unit10 - [Deploy] CI/CD  (0) 2023.04.03
ToDolist하면서 코드 이해하기  (0) 2023.04.02
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함