REST API 란 무엇인가?

jonghyun.log·2023년 1월 24일
0

HTTP

목록 보기
1/1
post-thumbnail

웹 개발을 하면 필연적으로 만나는 REST API 에 대해 공부한 내용을 정리하는 글 입니다.

부끄럽지만 필자는 여태껏 개발하면서 REST API 에 대해 제대로 공부해본 적이 없었다.

그래서인지 Swagger 를 이용해서 만든 api 문서가 restful 하지 못하다는 피드백을 받아서

이번 기회에 공부하고 정리하는 시간을 가져보려고 한다.

API(Application Programing Interface) 란?

컴퓨터의 기능을 실행시키거나 어떠한 응용프로그램에서 데이터를 주고 받기 위한 방법을 의미한다.

예를 들어 특정 문자열을 출력하는 문법이 자바에서는

System.out.Println("안녕하세요");

이라면 파이썬에서는

print('안녕하세요')

일 것이다. 이런식으로 특정 데이터를 출력하는 기능을 실행시키거나 혹은

브라우저 주소창에 www.naver.com 이라는 값을 입력하면 네이버 사이트가 출력되는것도

네이버 서버로부터 통신을 통해 html과 여러 데이터 값을 받았기 때문에 api라고 볼 수 있다.

REST API 란?

자 그렇다면 REST API 란 대체 무엇일까?

REST API 는 위의 예시중에서 www.naver.com 를 브라우저에 입력해서 네이버 사이트로 이동한 것처럼

내 컴퓨터가 아닌 다른 컴퓨터를 실행시키는 api 를 보다 효율적으로 사용하기 위해 고안된 개념으로

http 통신을 통해 자원을 보다 효율적으로 관리하기 위해 사용한다.

또한, HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고,
HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미한다.

Resource

특정 애플리케이션이 가진 데이터를 REST API 에서는 Resource 라고 한다.

가령, 우리가 사용하는 블로그 글 데이터를 생각해보면 블로그 글 테이블에는 다음과 같은 데이터가 있을 것이다.

idtitlebody
1api 알아보기api는 어쩌고..
2http란?http는 저쩌고...
3Spring 개발스프링으로...
4rest...
.........

위와 같은 데이터를

  • Collection
  • Element

이 두가지로 정의를 한다.

Collection

위 테이블의 데이터를 모두 지칭하는 것으로

http://blog.com/topics

와 같이 도메인경로/(복수형의 데이터) 형식으로 표현한다.

위 테이블이 topics 라면 테이블의 모든 데이터를 지칭하게 된다.

Element

위 테이블의 특정 데이터를 지칭하는 것으로

http://blog.com/topics/1 처럼

도메인경로/(테이블 혹은 데이터 이름)/(특정 값) 의 형식으로 표현하게 된다.

만약, 1이 id 를 의미한다면 위 테이블의 1번째 줄을 지칭하게 된다.

(Element 에서는 id 값을 식별값으로 사용하는것이 일반적이며,
이름으로 식별할 수 있다면 http://blog.com/topics/rest 처럼 단수형을 사용한다.)

즉, Element 가 모여있는 것이 Collection ,
Collection 의 하나 하나의 데이터를 Element 라고 한다.

CRUD 란

하지만, 위에서 살펴본 URL 을 사용하는 방식으로는 데이터 식별밖에 하지 못하며 데이터를 가공하지는 못한다.
따라서 이를 해결하기 위해 REST API 에서는 CRUD 를 사용한다.

CRUD는 Create, Read, Update, Delete 의 앞글자를 따서 만든 용어로
말 그대로 데이터를 생성(Create), 수정(Read), 갱신(Update), 삭제(Delete) 를 의미한다.

이런 작업을 REST API 에서는 Method 라고 부른다.

또한, 각각의 메서드는 HTTP Method 와 다음과 같이 매핑되어 사용된다.

  • Create - Post
  • Read - Get
  • Update - Put/Patch
  • Delete - Delete
    (왼쪽이 CRUD, 오른쪽이 HTTP Method)

예제를 통해 알아보기

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        }
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

다음과 같은 JSON 을 가지고 각각의 요청을 보내서 적용시켜 보도록 하자.

POST - Create(생성)

POST 요청은 데이터를 생성(CREATE) 할때 사용하는 HTTP METHOD

가령 위의 JSON 데이터가 DB 에 있을때 서버로

'topic' 에 해당하는 데이터를 바디에 담아서

{
	"title" : "API",
    "body" : "API 란... 어쩌고..."
}

서버 도메인/topics 라는 경로로 POST 요청을 보내게 되면

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        },
      	{
            "id" : 2,
			"title" : "API",
    		"body" : "API 란... 어쩌고..."
		}
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

이런식으로 데이터가 추가되게 될 것이다.

응답 헤더

개발자 도구를 통해 네트워크 탭에서 방금 보낸 요청의 서버에서 보내준 응답 헤더를 조회 해보면
응답 코드로 201과 응답 메시지로 "created" 라는 메시지가 왔음을 확인할 수 있다.
(여기서 응답코드 201은 데이터가 성공적으로 생성되었음을 의미한다. )

즉, REST API 에서는 특정 요청을 보내게 되면, 서버에서 그 요청에 대한 응답으로 응답 코드와 응답 메시지를 Response Header(응답 헤더) 라는 곳에 담아서 보내준다.

GET - Read(조회)

GET 요청은 데이터를 조회 할때 사용하는 메서드이며,

여러개를 묶어서(Collection) 를 조회 하느냐 혹은 하나의 데이터(Element) 조회 하느냐 하는 두가지의 방식이 존재한다.

GET 요청에는 요청 바디에 값을 담아서 보낼 필요가 없다.

1. 여러개를 묶어서(Collection) 조회

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        },
      	{
            "id" : 2,
			"title" : "API",
    		"body" : "API 란... 어쩌고..."
		}
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

데이터베이스에 다음과 같은 데이터가 들어 있을때 topics의 데이터를 묶어서 전부 가져오고 싶으면

서버 도메인/topics 라는 경로로 GET 요청을 보내면 된다.

그러면 Response Body에 다음과 같이 topics 데이터들이 담겨서 오게 될 것이고

응답 헤더에는 다음과 같이 상태 코드 200 과 함께 통신이 성공적으로 이루어졌다는 응답 메시지 OK 가 있을 것이다.

2. 하나의 데이터(Element) 조회

이번에는 하나의 데이터를 조회해보자.

위에서 특정 Element 를 url로 표현하는 방법이 기억나는가?

바로 도메인경로/(테이블 혹은 데이터 이름)/(특정 값) 으로 표현하면 됐었다.

서버에 요청을 보낼때도 이와 똑같은 방법으로 보내면 되므로

서버 도메인/topics/2 라는 경로로 GET 요청을 보내보자.

이 표현식은 topics 데이터중 아이디 값이 2인 것을 의미한다.
(여기서 2라는 값은 아이디일수도 있고 다른 값을 수도 있지만 서버에서 정하기 나름이므로 편의상 id 값이라고 하자.)

그러면 응답으로

응답 바디에 다음과 같은 데이터가 담겨서 올 것이고 헤더는 Collection 을 조회할 때와 똑같은 값이 담길것이다.

PUT/PATCH - Update(갱신, 수정)

Update 만 특이하게도 HTTP Method 와 두개와 매칭되며 두 메서드는 각각

  • PATCH - 부분 수정
  • PUT - 전체 수정

을 의미한다.

또한, PUT/PATCHPOST 와 같이 요청 바디에 데이터를 담아서 보내야 한다.

PATCH 로 부분 수정하기

위의 데이터에서 topicsid 가 2인 데이터를 수정해보자.

이 데이터의 title 만 변경하고 싶으면

{
	"title" : "patch"
}

요런 식으로 변경하고 싶은 데이터를 바디에 담고PATCH 요청을 사용하면 된다.

이제, URI 표기로 서버 도메인/topics/2 라는 경로로 바디에 담은 데이터와 함께 PATCH 요청을 보내보자.

그러면 결과로

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        },
      	{
            "id" : 2,
			"title" : "patch",
            "body" : "API 란... 어쩌고..."
		}
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

이렇게 값이 변경된 것을 확인해 볼 수 있다.

즉, PATCH 메서드는 바디에 넣어준 부분만 변경되고 나머지 부분은 변경되지 않는다.

PUT 으로 부분 수정하기

PUTPATCH 와 다 똑같지만 데이터가 변경되는 결과 측면에서 다르다.

위에서 보낸 PATCH 요청과 동일하게 설정하고 메서드 방식만 PUT 으로 요청을 보내보면

결과로

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        },
      	{
            "id" : 2,
			"title" : "patch"
		}
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

다음과 같이 데이터베이스의 데이터가 변경된다.

여기서 주목해봐야 할 부분은
topicsid가 2인 데이터의 "body" : "API 란... 어쩌고..." 라는 부분이 날아갔다는 점이다.
즉, PUT 메서드를 사용하면 바디로 넣어준 값을 덮어쓰기 때문에 수정하려는 값을 넣어준 부분과 식별자인 id를 제외하고 다른 부분이 사라진다.

DELETE - Delete(삭제)

DELETE 요청도 GET과 마찬가지로 바디에 값을 담을 필요없이 요청만 보내면 되며,

  • 한개의 Element 만 삭제
  • 여러개를 묶어서(Collection) 삭제

이렇게 두가지 방식이 존재한다.

한개의 Element 만 삭제

여기서도 topicsid가 2인 데이터를 삭제해 보도록 하겠다.

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        }
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

서버 도메인/topics/2 라는 경로로 DELETE 요청을 보내면 위와 같이topicsid가 2인 데이터가 삭제된다.

여러개를 묶어서(Collection) 삭제

이 경우에는 만약 topics 데이터 콜렉션을 삭제하고 싶으면

서버 도메인/topics 라는 경로로 DELETE 요청을 보내면 topics의 데이터들이 모두 삭제된다.

하지만, 이런 삭제 요청은 위험하기 때문에 보통 서버에서 이런 요청을 수행하지 못하도록 LOCK을 걸어두는 경우가 많다.

복잡한 데이터 관계 URI로 표현하기

{
    "topics": [
        {
            "id": 1,
            "title": "REST",
            "body": "REST is ..."
        }
    ],
    "comments": [
        {      
            "id": 1,
            "body": "POST is ...",
            "topicId":1 
        },
        {
            "id": 2,
            "body": "READ comments is ...",
            "topicId":1 
        }
    ]
}

다음과 같은 데이터가 있다고 가정해보자.

그러면 이번에는 comments 들을 URI 경로 표현식으로 표현해보고 싶다.

간단하게 생각하면

도메인주소/comments 나 혹은 도메인주소/comments/1 처럼 전체 댓글 콜렉션을 지칭하거나

댓글의 아이디가 1인 엘리먼트를 지칭할수도 있다.

하지만, 만약 topics 안에 정의되어 있는 댓글을 지칭하고 싶으면 어떤식으로 하면 될까?

데이터를 잘 관찰해보면 topicsid는 1이고 commentstopicId는 1이다.

즉 위의 데이터의 댓글들은 id가 1인 topic 에 종속되어 있다.

이때도 근본적인 원리는 크게 다르지 않다.

id가 1인 topic 에 종속된 모든 댓글을 지칭하고 싶으면
도메인주소/topics/1/comments 이런식으로 사용하면 되고

id가 1인 topic 에 종속되고 아이디가 2인 댓글을 지칭하고 싶으면
도메인주소/topics/1/comments/2 이런식으로 사용하면 된다.

위처럼 URI 를 사용하고 위에서 다룬 HTTP METHOD를 적절하게 적용해서 CRUD 를 구현하면 되겠다.

정리

즉, REST APIHTTP 를 이용해서 통신할 때 RESOURCEURI"표현" 하고
표현한 리소스에 적용할 "행위"METHOD
그에 따른 "결과"응답코드응답 메시지 로 적용시키는 일종의 "약속" 이라고 할 수 있다.

요청에 따른 응답코드들

위에서 다룬 응답코드들 말고 HTTP 에 정의된 다른 응답코드들도 다음과 같은 것들이 있다.

  • 200 : 클라이언트 요청 정상수행 (응답에 대한 메시지가 포함)
  • 201 : 리소스 생성 요청에 대한 정상처리
  • 202 : 리소스 생성 요청이 비동기적으로 처리될 때 사용
  • 204 : 클라이언트 요청 정상수행 (응답에 대한 메시지 미포함, 보통 삭제요청에 사용)
  • 400 : 클라이언트 요청이 부적절할 때 사용 (부적절한 이유를 응답 Body에 넣어줘야 함)
  • 401 : 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청할 때 사용
  • 403 : 클라이언트가 인증상태와 무관하게 응답하고 싶지 않은 리소스를 요청할 때 사용 (400 사용을 권장)
  • 404 : 클라이언트가 요청한 리소스가 존재하지 않을 때 사용
  • 405 : 클라이언트가 불가능한 메소드를 사용했을 때

공부한 내용 프로젝트에 적용해보기

REST API 에 대해 공부하기 전에 작성한 API 문서의 일부를 가져와봤다.....
공부하고 보니 킹받네...

HTTP METHOD 로 이 api 의 "행위" 를 표현할 수가 있으므로 굳이 api 경로에 create, delete 이런 불필요한 단어를 빼버렸다.

편-안

참고한 자료

생활코딩 rest api 강의

https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html

https://memostack.tistory.com/180#article-2--http-method%EC%99%80-crud

0개의 댓글