ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [2019.04.23] API 서버를 만들어보자 - http 방식
    개발 블로깅/Server&DataBase 개념 2019. 4. 23. 11:22

    node.js를 이용한 API를 직접 만들어 볼 기회가 올 줄이야. 정말 내가 원하는 작업이였다...ㅜㅜ (그렇다고 백엔드를 갈구하는 편은 아니다..)

     

    지금부터 API 서버를 만들어 보는 작은 프로젝트를 작업해보자.

     

    프로젝트로 쓸 디렉토리 생성

    mkdir serverProject
    
    cd serverproject
    

     

     

    module 관리자 package.json 생성

    npm init -y
    

     

     

    서버 개발 중 코드를 작업 후 저장하면 바로 적용되는 nodemon 모듈을 로컬로 설치 (새로고침을 안해도 됨)

    npm i -D nodemon

     

     

    package.json에 nodemon 설정 (npm start 명령어로 바로 실행 시킬 수 있도록 설정)

    {
      "name": "testServer",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "./node_modules/nodemon/bin/nodemon.js server/runServer.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "nodemon": "^1.18.11"
      }
    }
    // package.json 파일

     

     

    이제 VSCode를 켜서 서버와 클라이언트로 쓸 파일을 생성한다. 

    각 파일 정보

    • index.html : 서버에게 요청 및 응답받을 클라이언트
    • server/runServer.js : 서버를 생성하여 돌릴 파일 (경로 주의)
    • server/handle_Server.js : 실제 서버가 요청, 응답에 대한 작업을 처리하는 파일 (경로 주의)

     

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    
    </head>
    <body>
      <input type="text" id='inputText' />
      <input type="button" id="btn" value="go" onclick="test()" />
      <input type="text" id='resultText' />
      
      <script>
        function test(){
          var input = document.getElementById('inputText').value;
        }
      </script>
    </body>
    </html>

    클라이언트는 최대한 간결하게 만들었다.

    왼쪽 인풋박스는 서버에 요청 값을 보낼 박스, 오른쪽 input은 응답받아서 표시할 박스이다.

     

    # server/runServer.js

    const http = require('http'); // node에 내장된 http 모듈
    const handle = require('./handle_Server'); // 실제 요청, 응답 작업을 처리할 파일
    
    const port = 3000;  // 서버 요청 포트
    const ip = '127.0.0.1'; // 서버 ip
    
    const server = http.createServer(handle); // 서버 생성
    server.listen(port, ip); // 서버 접속경로 설정

     

    서버를 생성해주는 부분이다. 서버를 직접 작업하는 파일을 따로 분리시켜놔서, require로 받아서 사용한다.

     

    # server/handle_Server.js

    const requestHandler = function (request, response){
    
      const headers = defaultCorsHeaders;
      headers['Content-Type'] = 'text/plain'; // 응답하는 컨텐츠의 자료 타입을, 응답 헤더에 기록
    
      let statusCode = 200;  // 200 : 요청 성공, 404: 실패
      let responseValue = '';
    
      if(request.method === 'POST'){
        
      }else if(request.method === 'GET'){
    
      }else if(request.method === 'OPTIONS'){
    
      }
      response.writeHead(statusCode, headers);
      response.end(JSON.stringify(responseValue));
    }
    
    const defaultCorsHeaders = { // 요청에 맞는 
      'access-control-allow-origin': '*',
      'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'access-control-allow-headers': 'content-type, accept',
      'access-control-max-age': 10 // Seconds.
    };
    
    module.exports = requestHandler; // 외부에서 사용할 수 있도록 exports

     

    기본적인 세팅이다. 클라이언트에서는 요청 방식이 POST,GET,PUT,DELETE 방식 중 하나를 쓰지만, 일반적으로는 GET,POST를 쓰므로, 이렇게 설정을 해준다.

    ∴ OPTIONS란? 클라이언트는 서버에게 요청을 보내면 두개의 신호를 보낸다. 하나는 서버에 요청 및 응답이 잘 되는지 테스트 신호인 OPTIONS, 두번째가 실제 클라이언트가 보내고자 하는 방식의 신호를 보낸다.

     

    첫번째 신호인 OPTIONS가 응답 및 요청에 실패를 하면, 두번째 신호는 보내지 않고 바로 요청 실패로 처리한다.

     

    이제 우리는 클라이언트가 소문자 알파벳을 보내면, 서버는 대문자로 변환하여 응답을 보내는 작업을 해보자.

     

    # index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    
    </head>
    <body>
      <input type="text" id='inputText' />
      <input type="button" id="btn" value="go" onclick="test()" />
      <input type="text" id='resultText' />
      
      <script>
        function test(){
          var input = document.getElementById('inputText').value;
    
          fetch('http://localhost:3000/upper',{
            method: 'POST',
            body: JSON.stringify(input),
            headers: {
              'content-type': 'text/json'
            }
          })
          .then(res => {res.json()})
          .then(res => {document.getElementById('resultText').value = res;});
    
        }
      </script>
    </body>
    </html>

     

    fetch 서버요청 방식은 앞 단에서 배웠을 것이다. 위 와 같이 입력한 내용을 서버에게 보내는 POST 요청 방식을 한다. (경로에 주의한다.)

    서버에게 응답받은 데이터를 오른쪽 input 박스에 넣는 작업을 한다.

     

    # handle_Server.js

    클라이언트에게서 데이터를 받는 방식은 아래와 같다.

        let body = ''; // 클라이언트가 보낸 데이터를 담을 변수
        request.on('data', data => {
          body += data.toString(); // 버퍼 상태의 데이터를 데이터로 변환(?)
        }); 

    왜 이렇게 되는지는 모르겠다. 그냥 외워야 한다.

     

    데이터를 클라이언트에게 보내느 방식은 아래와 가다.

        request.on('end', () => {
          response.writeHead('200', headers);
          response.end('보낼 데이터');
        }

     

    그럼 위 방식을 이용해서 handle_Server.js 파일을 적절히 작업해보자. 조금 복잡할 수 있다...

    const requestHandler = function (request, response){
    
      const headers = defaultCorsHeaders;
      headers['Content-Type'] = 'text/plain'; // 응답하는 컨텐츠의 자료 타입을, 응답 헤더에 기록
    
      let statusCode = 200;  // 200 : 요청 성공, 404: 실패
      let responseValue = '';
    
      if(request.method === 'POST'){
        let body = ''; // 클라이언트가 보낸 데이터를 담을 변수
        request.on('data', data => {
          body += data.toString(); // 버퍼 상태의 데이터를 데이터로 변환(?)
        });                         // 사실 나도 여기는 잘 모르겠다..
    
        request.on('end', () => {
          if(request.url === '/upper'){
            responseValue = body.toUpperCase();
          }else if(request.url ==='/lower'){
            // 미구현
          }
          response.writeHead(statusCode, headers); // 응답헤더 설정
          response.end(responseValue); // 응답 메세지 전달 및 서버 요청 종료
        }
        );
      }else if(request.method === 'GET'){
        
      }else if(request.method === 'OPTIONS'){
        response.writeHead(statusCode, headers);
        response.end('1');
      }
      
    }
    
    const defaultCorsHeaders = { // 요청에 맞는 
      'access-control-allow-origin': '*',
      'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'access-control-allow-headers': 'content-type, accept',
      'access-control-max-age': 10 // Seconds.
    };
    
    module.exports = requestHandler; // 외부에서 사용할 수 있도록 exports

     

     

    제대로 서버에 요청하고 대문자로 변환된 데이터를 받아오는 것을 확인할 수 있다.

    반응형

    댓글

Designed by Tistory.