simple api 만들기

이석원·2022년 7월 30일
0

간단한 api 를 만들었다. 코멘트로 설명한다.

const http = require("http");
//http 는 문자열을 기본으로 하기 때문에 숫자를 쓰려면 특정한 방식이 필요하다. 
//id:=19 --> 이와 같이 한다. 이 방법을 따르지 않는다면 id : "19" 와 같이 나온다.
//httpie 는 출력할 때 일정한 순서를 따르기 때문에 내가 쓴 순서와 달라질 수 있다. 넘어가자.
const users = [
  {
    id: 1,
    name: "Rebekah Johnson",
    email: "Glover12345@gmail.com",
    password: "123qwe",
  },
  {
    id: 2,
    name: "Fabian Predovic",
    email: "Connell29@gmail.com",
    password: "password",
  },
];

const posts = [
  {
    id: 1,
    title: "간단한 HTTP API 개발 시작!",
    content: "Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.",
    userId: 1,
  },
  {
    id: 2,
    title: "HTTP의 특성",
    content: "Request/Response와 Stateless!!",
    userId: 1,
  },
];

const server = http.createServer();

const httpRequestListener = (request, response) => { 
  //request,response 는 무조건 특정 객체가 인자로 주어진다. 
  //가장 아래 있는 server.on("request", callback) 때문이다. 
  //서버는 특정 포트에서 이벤트를 기다리다가 request 가 발생하면 콜백 함수를 실행한다.

  const { url, method } = request; 
  //구조 분해 할당. request 안에 있는 url, method 의 프로퍼티 값을 url 과 method 의 value 로 준다. 
  //따라서 식의 오른쪽에 있는 객체(request)에 동일한 이름의 key 값이 있어야 한다.

  if (method === "GET") { //ping pong. 메소드
    if (url === "/ping") { 
      //url 은 http -v GET 127.0.0.1 :8000/ping... 에서 포트 번호 뒤에 있는 위치를 말함.
      //convention : (REST) GET,POST,DELETE,PATCH 등은 컴퓨터에게 시키는 동작. 뒤에 url 은 
      //그 동작의 목적지다. 목적지는 구체적으로 해야 한다. 예를 들어서 ports/1 처럼 한다. 1은 posts 의 
      //postid 를 의미한다.
      response.writeHead(200, { "Content-Type": "application/json" });
      //response 객체의 writeHead 프로퍼티에 status code 를 먼저 넣어준다. 
      //상황에 맞게 넣어줘야 프론트와 평화를 유지할 수 있다. 
      response.end(JSON.stringify({ message: "pong" }));
      //response.end() 는 함수다. 이벤트 기반이 아니다. 따라서 순차 실행된다. 모든 이벤트가 끝났을 때 실행된다.
      //함수는 response 를 요청이 들어온 곳으로 돌려준다. 함수안의 값은 없어도 된다. 
    } else if (url === "/posts") {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ posts: posts }));
    } else if (url.startsWith("/users")) { 
      //url 문자열이 /users 로 시작된다면 true 를 반환. 아니라면 false. 
      //str.startsWith(searchingString) 이 형식이다. 
      const userId = parseInt(url.split("/")[2]); //url 은 문자열이기 때문에 반드시 숫자로 바꿔줘야 아래 함수들이 의도한대로 작동한다.
      const user = users.find((user) => user.id === userId);
      //find 는 true 를 만나면 중지됨. 콜백 함수의 값을 반환한다. 따라서 불필요한 연산을 막을 수 있다.
      const results = posts.filter((post) => post.userId === userId);
      //filter 는 참값인 원소만 모아서 새로운 배열로 반환한다. 
      user.posts = results;
      //results 는 filter 함수에서 받아온 배열을 가리킨다.
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ data: user })); //끝을 내기 위해 필수임. 요청이 들어왔던 곳으로 respose 를 날려준다. 함수다. 이벤트 기반 아님.
    }
  } else if (method === "POST") { //user 신규 등록
    if (url === "/users/signup") {
      let rawData = "";

      request.on("data", (chunk) => {
        rawData += chunk;
      });
      //조각조각 들어오는 데이터를 모으고 합친다. 버퍼와 스트림 참조.
      request.on("end", () => {
        const user = JSON.parse(rawData); //모은 데이터를 자바스크립트 객체로 바꾼다. 통신상의 데이터는 상당수가 JSON 이다.
        //request.on() 이벤트를 등록. data 가 들어오는 이벤트가 끝난 후 end 이벤트가 시작된다. 
        users.push({
          id: user.id,
          name: user.name,
          email: user.email,
          password: user.password,
        });
        response.writeHead(201, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "SUCCESS" }));
        //위에 썼듯이 작업을 완전히 종료시키기 위해서 response.end() 는 반드시 필요하다. 
        //response.writeHead 의 status code 를 정확히 등록해야 프론트가 작업하기 좋다.
      });
    } else if (url === "/posts") { //게시글 등록. 메소드는 POST
      let rawData = "";

      request.on("data", (chunk) => {
        rawData += chunk;
      });

      request.on("end", () => {
        const post = JSON.parse(rawData);
        const user = users.find((user) => user.id === post.userId);

        if (user) { //만약 없는 user 라면 실행이 안된다. 
          posts.push({
            id: post.id,
            name: post.title,
            content: post.content,
            userId: post.userId,
          });

          response.writeHead(201, { "Content-Type": "application/json" });
          response.end(JSON.stringify({ message: "SUCCESS" }));
        } else { //user 가 없을 경우 실행 된다. 
          response.writeHead(404, { "Content-Type": "application/json" });
          response.end(JSON.stringify({ message: "NOT FOUND" }));
        }
      });
    }
  } else if (method === "PATCH") {
    if (url.startsWith("/posts")) {
      let rawData = "";

      request.on("data", (chunk) => {
        rawData += chunk;
      });

      request.on("end", () => {
        const postId = parseInt(url.split("/")[2]); // posts/id/1
        const data = JSON.parse(rawData); 

        const post = posts.find((post) => post.id === postId); 

        post.title = data.title; //수정이 목적이기 때문에.
        post.content = data.content; 

        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ post: post })); 
      });
    }
  } else if (method === "DELETE") { //특정 게시물 삭제
    if (url.startsWith("/posts")) {
      const postId = parseInt(url.split("/")[2]);
      const indexOfPostId = posts.findIndex((post) => post.id === postId);

      delete posts[indexOfPostId]; //delete 는 null 을 남긴다. 다른 삭제 방법인 splice 를 쓰자. 
      //posts.splice(indexOfPostId, 1);

      response.writeHead(204, { "Content-Type": "application/json" });
      response.end(
        JSON.stringify({
          message: "NO_CONTENT",
        })
      );
    }
  }
};

server.on("request", httpRequestListener);
server.listen(8000, "127.0.0.1", function () {
  console.log(`Listening to request on 127.0.0.1:8000`);
});
//on 은 이벤트 등록을 한다. server.on("request", callback) 은 request 를 간절히 기다린다. 
//req 가 왔을 경우 콜백 함수를 실행한다. listen 은 특정 포트에서 이벤트를 듣는다는 의미다. 하세요
profile
개발자 공부중

0개의 댓글