본문 바로가기
TIL with Programmers

[TIL] 9/5 api GET/DELETE/PUT, 리팩터링, forEach, map, HTTP 상태코드

by 보먀 2024. 9. 5.
728x90
반응형

1. 실습

<API 설계 (URL, method)>

 

1) 전체 유튜버 "조회" GET /youtubers

- req: X

- res: map 을 전체 조회해서 돌려주면 됨

 

2) 개별 유튜버 "조회" GET /youtuber/:id 

- id 로 map 에 저장된 객체를 찾아서, 그 객체의 정보를 뿌려줌

- req: params.id, map 에 저장된 key 값을 전달

- res: map 에서 id 로 객체를 조회해서 전달

 

3) 신규 유튜버 "등록" POST /youtuber

- { channelTitle: ___ , sub: 0, videoNum: 0 } 

- req: channeTitle 만 주고 API 내부적으로 sub, videoNum 을 만들게 해도 괜찮고,

          아니면 channerTitle, sub, videoNum 을 모두 줘도 괜찮음 (나는 후자의 방법으로 구현)

- res: "channelTitle 님, 유튜버 생활을 응원합니다!" 메세지를 돌려줌

 

4) 개별 유튜버 "삭제" DELETE /youtubers/:id

- req: params.id

- res: "channelTilte님, 아쉽지만 다음에 또 뵙겠습니다."

 

5) 전체 유튜버 "삭제" DELETE /youtubers

- req: X

- res: 지울 유튜버가 있는 경우 '전체 삭제 완료' 메세지 돌려줌, 지울 유튜버가 없는 경우 '삭제할 유튜버가 없습니다' 메세지 돌려줌

 

6) 개별 유튜버 "수정" PUT /youtubers/:id

- req: params.id, 바디에 channelTitle 

- res: "(이전)channelTitle님, 채널명이 (새로운)channelTitle로 변경되었습니다."

 

 

※ 2) 개별 유튜버 조회, 3) 신규 유튜버 등록은 여기에

https://everydayc0ding.tistory.com/entry/TIL-94-GET-POST-API-postman

 

[TIL] 9/4 GET, POST, API, postman

1. POST POST -> 생성(=등록)할 때 사용하는 method ex) 회원가입 = 나 등록해줘 => id, password, name, email, contact 그렇다면, GET 메소드의 URL 로도 정보를 보낼 수 있지 않나? X-> post 로 보내는 정보들은 등록

everydayc0ding.tistory.com

 

 

1.1. 전체 유튜버 조회

 

방법1) forEach 문을 사용해서 각 요소를 돌면서 요소의 index 값을 key 값으로 사용

// 전체 유튜버 조회
app.get('/youtubers', (req, res) => {
    var youtubers = {};
    db.forEach(function(value, key) {
        youtubers[key] = value;
    });
    res.json(youtubers);
})

 

 

방법2) forEach 문을 사용해서 각 요소를 돌면서 객체의 채널명을 key 값으로 사용

app.get('/youtubers', (req, res) => {
    var youtubers = {};
    db.forEach(function(youtuber) {
        console.log(youtuber);
        youtubers[youtuber.channelTitle] = youtuber;
    });
    res.json(youtubers);
    
})

 

 

1.2. 개별 유튜버 삭제

 

// 개별 유튜버 삭제
app.delete('/youtubers/:id', (req, res) => {
    let {id} = req.params;
    id = parseInt(id);
    let youtuber = db.get(id);
    if (youtuber) {
        db.delete(id);
        res.json({
            message: `${youtuber.channelTitle}님 아쉽지만 다음에 또 뵙겠습니다.`
        });
    } else { // 예외처리
        res.json({
            message: `요청하신 ${id}번은 없는 유튜버입니다`
        })
    }
})

 

참고로 지금은 예외처리를 할 때 메세지를 보내지만, 실제로는 프론트엔드 쪽에서 메세지 틀을 가지고 있는 경우가 많기 때문에 백엔드에서는 프론트로 id 값만 보내주면 된다. 

 

 

1.3. 전체 유튜버 삭제

 

db.size 가 1 이상이면 Map 을 비워주고, 만약 삭제할 유튜버가 없다면 삭제할 유튜버가 없다는 메세지를 보낸다. 

사실 삭제할 유튜버가 없을 때 db.clear() 을 써줘도 에러가 나진 않지만, 따로 처리해주는 것이 좋다. 

// 전체 유튜버 삭제
app.delete('/youtubers', (req, res) => {
    let msg = "";
    if (db.size) {
        db.clear();
        msg = '전체 삭제 완료';
    } else {
        msg = '삭제할 유튜버가 없습니다';
    }
    res.json({
        message: msg
    })
})

 

 

1.4. PUT

 

기존 db 의 객체를 변수에 넣어놓고, channelTitle 값을 리퀘스트 바디에 들어온 channelTitle 으로 고쳐준다. PUT 메서드는 덮어씌우는 메서드이기 때문에 channelTitle 이 수정된 객체(변수에 넣어놓은)를 통채로 db 에 덮어 씌워주면 된다. 

// 개별 유튜버 수정
app.put('/youtubers/:id', (req, res) => {
    let {id} = req.params;
    id = parseInt(id);
    let youtuber = db.get(id);

    if (youtuber) {
        let newTitle = req.body.channelTitle;
        let oldTitle = youtuber.channelTitle;
        youtuber.channelTitle = newTitle;
        db.set(id, youtuber);
        res.json({
            message: `${oldTitle}님, 채널명이 ${newTitle}로 수정되었습니다`
        })
    } else {
        res.json({
            message: `요청하신 ${id}번은 없는 유튜버입니다`
        })
    }
})

 

 

※ 참고 - 메서드는 정육면체, 프로퍼티는 직육면체

 

뭘 사용해야할지 모를 때 점(.)을 누르면 여러가지가 뜨는데, 여기서 정육면체는 메서드를 나타내고 직육면체는 프로퍼티를 나타낸다.

  • 정육면체 -> ___.메서드이름()
  • 직육면체 -> ___.프로퍼티

 

 

 

4. HTTP 상태코드

HTTP -> 인터넷 상에서 통신할 때 사용하는 규약

상태코드 -> HTTP 안에 들어있는 

 

 

4.1. 200 OK

-> 서버가 요청을 제대로 처리함 

-> 조회 / 수정 / 삭제 성공

 

4.2. 404 Not Found

-> 찾으려고 하는 페이지 없음 (url 에 맞는 api 없음)

 

4.3. 그 외에 상태 코드들

 

- 201: 성공적으로 요청되었으며, 등록도 성공 (POST 할 때 주로 사용됨)

- 403: 서버가 요청 거부 (로그인 시 관리자가 아니라 관리자 페이지 접근 금지시)

- 500: 내부 서버에 요류가 발생하여 요청 수행이 불가 (서버 터진거 아니야? 할 때 보통 이 상태코드, 서버가 크리티컬한 오류 맞았을 때)

 

가장 대표적인 몇가지 상태코드이고 이 외에도 많은 상태코드들이 있는데 간략하게 정리하면 이렇다.

  • 1xx (정보): 요청을 받았으며 프로세스를 계속한다
  • 2xx (성공): 요청을 성공적으로 받았으며 인식했고 수용하였다
  • 3xx (리다이렉션): 요청 완료를 위해 추가 작업 조치가 필요하다
  • 4xx (클라이언트 오류): 요청의 문법이 잘못되었거나 요청을 처리할 수 없다
  • 5xx (서버 오류): 서버가 명백히 유효한 요청에 대해 충족을 실패했다

 

더 많은 내용은 여기를 참고하자.

https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C

 

HTTP 상태 코드 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 아래는 HTTP(하이퍼텍스트 전송 프로토콜) 응답 상태 코드의 목록이다. IANA가 현재 공식 HTTP 상태 코드 레지스트리를 관리하고 있다. 모든 HTTP 응답 코드는 5개의

ko.wikipedia.org

https://developer.mozilla.org/ko/docs/Web/HTTP/Status

 

HTTP 상태 코드 - HTTP | MDN

HTTP 응답 상태 코드는 특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다. 응답은 5개의 그룹으로 나누어집니다: 정보를 제공하는 응답, 성공적인 응답, 리다이렉트, 클라이언트 에러, 그리고

developer.mozilla.org

 

 

 

4. 리팩토링

소프트웨어의 코드 내부(구조)를 변경하는 것 -> 이해하기 쉽게, 성능 좋게, 안정성 높게

그래서 우리는 리팩토링을 통해 클린 코드를 가질 수 있게 된다. 

 

그렇다면 리팩토링은 언제 해야 하는 거지?

1) 에러(문제점)이 n 회 발견되었을 때 리팩토링을 해야 함
2) 리팩토링을 하면서, 에러(문제점)을 발견할 수 있음
3) 기능을 추가하기 전  ex) API URL 설계  수정
4) 코드 리뷰할 때

※ 참고 - 리팩터링을 하면 안되는 시점: 배포 / 운영 직전 (절대로 하면 안됨)

 

 

강의에서 API 수정 또는 새롭게 API 를 만들 때마다, 중간중간에 테스트를 하면서 진행이 되었는데 그게 리팩터링이라는 것을 알게 되었다.

기존의 API 기능이 잘 돌아가는지 테스트 -> API 수정 or API 새롭게 만듦 -> 데이터 넣고 다시 테스트 -> 다 만들고 테스트 

 

 

 

5. forEach

배열의 각 요소에 대해 한 번씩 주어진 콜백 함수를 실행하는 배열 메서드이다. 이 함수는 반복할 때 사용하는 고차 함수 중 하나로, 배열의 요소를 변형하거나 작업을 수행할 때 유용하다.

array.forEach(function(element, index, array) {
    // 작업 내용
});

 

- element: 현재 처리 중인 요소

- index(선택적): 현재 처리 중인 요소의 인덱스

- array(선택적): forEach 가 호출된 배열 자체

 

 

배열 사용 예제

const arr = [1, 2, 3, 4, 5]
arr.forEach(function(a, b, c) {
    console.log(`a: ${a}, b: ${b}, c: ${c}`);
})

/*
a: 1, b: 0, c: 1,2,3,4,5
a: 2, b: 1, c: 1,2,3,4,5
a: 3, b: 2, c: 1,2,3,4,5
a: 4, b: 3, c: 1,2,3,4,5
a: 5, b: 4, c: 1,2,3,4,5
*/

 

 

근데 사실 forEach 는 이터러블(iterable)한 객체에서도 사용가능하다. 자바스크립트의 일반 객체는 이터러블하지 않아서 사용이 불가하지만, map 은 이터러블한 객체이기 때문에 forEach 사용이 가능하다.  map 에서 두번째 요소는 인덱스가 아니라 map 에서의 키 값이 들어간다. 

 

map 사용 예제

 

콘솔에 출력하면 map 객체의 키 값이 7, 9, 8 이 차례로 출력이 된다. 

let map = new Map();
map.set(7, "seven");
map.set(9, "nine");
map.set(8, "eight");

map.forEach((value, key, arr) => {
    console.log(value, key, arr);
})

 

 

 

6. map

map 은 배열의 각 요소를 순회하면서 주어진 콜백 함수를 호출하고, 그 결과를 새로운 배열로 반환한다. 콜백 함수가 반환한 값을 담은 새로운 배열을 반환하는 특징이 있다. 

const newArray = oldArray.map((element, index, array) => {
  // 작업 내용
  return newValue;
});

 

- element: 현재 처리 중인 배열의 요소

- index(선택적): 현재 요소의 인덱스

- array(선택적): map 을 호출한 원래 배열

 

const arr = [1, 2, 3, 4, 5]
arr.map(function(a, b, c) {
    console.log(`a: ${a}, b: ${b}, c: ${c}`);
})

/*
a: 1, b: 0, c: 1,2,3,4,5
a: 2, b: 1, c: 1,2,3,4,5
a: 3, b: 2, c: 1,2,3,4,5
a: 4, b: 3, c: 1,2,3,4,5
a: 5, b: 4, c: 1,2,3,4,5
*/

 

위의 코드는 forEach 문 배열 사용 예제 코드에서 forEach 를 map 으로만 바꾼 코드이다. 코드를 돌려보면 출력 결과 또한 같은 것을 알 수 있다. 그렇다면 어떤 부분이 다른 것일까?

 

바로 map 은 반환 값이 있다는 것이다.

forEach 는 콜백 함수의 return 값을 저장하거나 반환하지 않기 때문에 undefined 가 출력되고.

map 은 콜백 함수의 return 값을 새로운 배열에 저장해 반환한다. 

추가로 forEach, map 둘 다 원본 배열은 건드리지 않는 것을 확인할 수 있다. 

// 원본 배열
const arr = [1, 2, 3, 4, 5]

// forEach
const forEachArr = arr.forEach(function(a, b, c) {
    return a * 2;
})

console.log(arr); // [1, 2, 3, 4, 5]
console.log(forEachArr); // undefined

// map
const mapArr = arr.map(function(a, b, c) {
    return a * 2;
})

console.log(arr); // [1, 2, 3, 4, 5]
console.log(mapArr); // [ 2, 4, 6, 8, 10 ]

 

 

정리!

forEach
  • 단순히 배열을 순회하며 콜백 함수 실행
  • 콜백 함수의 리턴 값을 저장하거나 리턴하지 않음
map
  • 배열을 순회하면서 콜백 함수 실행
  • 콜백 함수의 리턴 값을 새로운 배열에 저장해서 반환

 

 

 

728x90
반응형