Proxy를 설정해 HTTP 통신하기

이동국·2022년 12월 10일
0
post-custom-banner

이번에는 페어와 함께 proxy를 설정하여 직접 서버와 http 통신을 시도해 보았다.

먼저 과제를 git clone 한 뒤, 백엔드의 개발 서버 역할을 해줄 api와, 프론트엔드의 개발 서버 역할을 해줄 my-app에 각각 접근하여 npm install을 하여주자.

그리고 api에 접근한 터미널에서는 npm run dev를, my-app에 접근한 터미널에서는 npm start를 통해 각기 개발 서버를 열자.

1. 과제1

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

package.json

우회할 api주소를 적어 주었다.

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

BookService.js

그리고 기존의 fetch, 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거하여주니 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();
}

과제2

레포지토리로 받아온 과제를 살펴보면 api2 라는 폴더가 존재하고 있다.
실제로 프로젝트 및 실무를 할 때, 하나의 도메인이 아닌 여러 개의 도메인에서 응답을 받아와야 하는 경우가 종종 있는데, 이럴 때는 유연하게 proxy를 설정할 필요가 있다.

이번에는 webpack dev server의 proxy 기능 대신 http-proxy-middleware의 proxy 기능을 사용하여 proxy를 유연히 설정해 2개의 도메인에서 모두 응답을 받아왔고, api2에 관련된 fetch 함수를 만들고, 컴포넌트를 하나 이상 만들어 2개의 도메인에서 모두 응답을 받아오는지 테스트 하여 보았다.

api2도 이렇게 실행을 시켜 주어야 한다.

package.json

하기전에 우회할 api주소를 지워주자.(맨 밑)

....
},

}

setupProxy.js

http-proxy-middleware 라이브러리 설치

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,
        })
    );
};

BookService.js

먼저 api2에 관련된 fetch 함수를 만들어 주었다.


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();
}

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

CreateBook의 컴포넌트와 거의 같게 만들었고 이름만 바꾸어 주었다.

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

DisplayBoard에서는 getAllTodo의 버튼이 클릭 될 때 실행 되도록 만들어 주었다.

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

BookTable과 비슷하게 만들었으며 이름만 바꾸어 주었다.

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;

완성

post-custom-banner

0개의 댓글