Proxy를 설정해 HTTP 통신하기

신창용·2023년 2월 6일
0

[Deploy] CI/CD

목록 보기
6/6
post-custom-banner

1. 과제1

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

package.json

// api/packge.json
....
},
	"proxy" : "http://localhost:3080"
}

BookService.js

기존의 fetch, 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거하여주니 CORS 에러를 해결됨

// my-app/services/BookService.js
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개의 도메인에서 모두 응답을 받아오는지 테스트 하여야 한다.

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의 컴포넌트와 복사하여 이름만 바꾸어 주었다.

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;
profile
코딩으로 쓰는 일기장
post-custom-banner

0개의 댓글