REST 구성REST 의 특징1) Uniform (유니폼 인터페이스)2) Stateless (무상태성)3) Cacheable (캐시 가능)4) Self-descriptiveness (자체 표현 구조)5) Client - Server 구조6) 계층형 구조REST API 디자인 가이드REST API 중심 규칙1) URI는 정보의 자원을 표현해야 한다. (리소스명은 동사보다는 명사를 사용)2) 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)로 표현HTTP 구조HTTP Headerstart lineheadersbodyContent-typeJSON 1. JSON(JavaScript Object Notation)이란?2. JSON(JavaScript Object Notation) 형식JSON 가져오기HTTP 1.0, 1.1, 2.0HTTP 1.0HTTP 1.1HTTP 2.0Head of line blocking(HOLB)
REST 구성
- 자원(RESOURCE) - URI
- 행위(Verb)
- 표현(Representations)
REST 의 특징
1) Uniform (유니폼 인터페이스)
- Uniform Interface는 URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일
2) Stateless (무상태성)
- REST는 무상태성 성격을 갖는다.(작업을 위한 상태정보를 따로 저장하고 관리하지 않음)
- 세션 정보나 쿠키정보를 별도로 저장하고 관리하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리하면 된다.
- 때문에 서비스의 자유도가 높아지고 서버에서 불필요한 정보를 관리하지 않음으로써 구현이 단순해짐
3) Cacheable (캐시 가능)
- REST의 가장 큰 특징 중 하나는 HTTP라는 기존 웹표준을 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 활용이 가능하다.
- 따라서 HTTP가 가진 캐싱 기능이 적용 가능합니다. HTTP 프로토콜 표준에서 사용하는 Last-Modified태그나 E-Tag를 이용하면 캐싱 구현이 가능하다.
4) Self-descriptiveness (자체 표현 구조)
- REST의 또 다른 큰 특징 중 하나는 REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조로 되어 있다는 것이다.
5) Client - Server 구조
- REST 서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조로 각각의 역할이 확실히 구분되기 때문에 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로간 의존성이 줄어들게 된다.
6) 계층형 구조
- REST 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수 있게 한다.
REST API 디자인 가이드
REST API 설계 시 가장 중요한 항목은 다음의 2가지로 요약할 수 있습니다.
- URI는 정보의 자원을 표현해야 한다.
- 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.
REST API 중심 규칙
1) URI는 정보의 자원을 표현해야 한다. (리소스명은 동사보다는 명사를 사용)
GET /members/delete/1
- 위와 같은 방식은 REST를 제대로 적용하지 않은 URI로, URI는 자원을 표현하는데 중점을 두어야 한다.
- delete와 같은 행위에 대한 표현이 들어가면 안됨
2) 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)로 표현
- 위의 잘못 된 URI를 HTTP Method를 통해 수정해 보면
DELETE /members/1
- 회원정보를 가져올 때는 GET, 회원 추가 시의 행위를 표현하고자 할 때는 POST를 사용하여 표현한다.
회원정보를 가져오는 URI
GET /members/show/1 (x)
GET /members/1 (o)
회원을 추가할 때
GET /members/insert/2 (x) - GET 메서드는 리소스 생성에 맞지 않습니다.
POST /members/2 (o)
HTTP 구조
HTTP Header

start line
- Request
GET /test.html HTTP/1.1
[HTTP Method] [Request target] [HTTP version]
- Response
HTTP/1.1 200 OK
[HTTP version] [Status Code] [Status Text]
headers
- 해당 request에 대한 추가 정보를 담고있다.
Host
: 요청하려는 서버 호스트 이름, 포트번호
Authorization
: 인증 토큰을 서버로 보낼때 사용(jwt)
Origin
: 서버로 Post 요청을 보낼 때 요청이 어느 주소에서 시작되었는지 나타내는 값, CORS 방지
Cookie
: kev-value 값으로 쿠키값 표현
Content-type
: Body에 들어갈 데이터 타입을 명시
- 그 외 다양한 부분들로 구성되어 있다.
body
- HTTP Request가 전송하는 데이터를 담고 있는 부분
- HTTP Body는 비어있을 수도 있다.
{
"test_id": "tmp_1234567",
"order_id": "8237352"
}
Content-type
HTTP Request는 아래와 같이 4개 파트로 나눌 수 있다.-

- 여기서 Message Body에 들어가는 타입을 HTTP Header에 명시할 수 있는데, Content Type 필드를 이용한다.
- ex) 텍스트 타입은 text/html, file 타입은 multipart/form-data, json 타입은 application/json 등
- URL
- application/json : RestFul API를 사용하게 되며 request를 날릴 때 대부분 json을 많이 사용하게 됨에 따라 자연스럽게 사용이 많이 사용, {key:value} 형태로 전송
- application/x-www-form-urlencoded는 html의 form의 기본 Content-Type, 보내는 데이터를 URL 인코딩이라고 부르는 방식으로 인코딩 후 보냄, key=value&key=value 형태로 전송
- mutipart/form-data : 파일 업로드의 경우 이 방식을 사용해야 됨. 메세지가 문자인지, 파일인지를 multipart의 파트별로 분리하여 개별 파일을 분리하여 전송
- URI
- URI는 특정 리소스를 식별하는 통합 자원 식별자(Uniform Resource Identifier)를 의미
- URI는 그 자체로, 이름+주소(Host+Path)이거나 이름이다.
- URL은 Scheme이 붙어, URI에 프로토콜이 결합된 형태이다.
따라서 golang의 경우, mime/multipart를 import하여 사용함.
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"mime/multipart"
)
type ProfileForm struct {
Name string `form:"name" binding:"required"`
Avatar *multipart.FileHeader `form:"avatar" binding:"required"`
// or for multiple files
// Avatars []*multipart.FileHeader `form:"avatar" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/profile", func(c *gin.Context) {
// you can bind multipart form with explicit binding declaration:
// c.ShouldBindWith(&form, binding.Form)
// or you can simply use autobinding with ShouldBind method:
var form ProfileForm
// in this case proper binding will be automatically selected
if err := c.ShouldBind(&form); err != nil {
c.String(http.StatusBadRequest, "bad request")
return
}
err := c.SaveUploadedFile(form.Avatar, form.Avatar.Filename)
if err != nil {
c.String(http.StatusInternalServerError, "unknown error")
return
}
// db.Save(&form)
c.String(http.StatusOK, "ok")
})
router.Run(":8080")
}

JSON
1. JSON(JavaScript Object Notation)이란?
- JSON은 경량(Lightweight)의 DATA-교환 형식
- Javascript에서 객체를 만들 때 사용하는 표현식을 의미한다.
- JSON 표현식은 사람과 기계 모두 이해하기 쉬우며 용량이 작아서, 최근에는 JSON이 XML을 대체해서 데이터 전송 등에 많이 사용한다.
- 특정 언어에 종속되지 않으며, 대부분의 프로그래밍 언어에서 JSON 포맷의 데이터를 핸들링 할 수 있는 라이브러리를 제공한다.
2. JSON(JavaScript Object Notation) 형식
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": [
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
}
]
}
- 하위 계층의 데이터에 접근하려면, 간단하게 프로퍼티 이름과 배열 인덱스의 체인을 통해 접근하면 된다.
- 예를 들어 superHeroes의 두 번째 member의 세 번째 power에 접근하려면
superHeroes['members'][1]['powers'][2]
- 우선 변수 이름은 —
superHeroes
이다.
members
프로퍼티에 접근하려면,["members"]
를 입력한다.
members
는 객체로 구성된 배열입니다. 두 번째 객체에 접근할 것이므로[1]
를 입력한다.
- 이 객체에서
powers
프로퍼티에 접근하려면["powers"]
를 입력한다.
powers
프로퍼티 안에는 위에서 선택한 hero의 superpower들이 있다.. 세 번째 것을 선택해야 하므로[2]
.
JSON 가져오기
- JSON을 가져오기 위해서는,
XMLHttpRequest
(때론 XHR)로 불리는 API를 사용하면 된다. - 이것은 매우 유용한 JavaScript 오브젝트로 JavaScript (e.g. images, text, JSON, even HTML snippets)를 통해 우리가 서버로 부터 다양한 리소스를 가져오는 요청을 만들어 준다.
- 즉, 전체 페이지를 불러오지 않고도 필요한 부분만을 업데이트 할 수 있다.
HTTP 1.0, 1.1, 2.0
- HTTP 1.0
- Header, status code, content-type 추가, 기존 Get에서 Post, Head 추가 제공
- 3 way handshake로 reqeust마다 연결함
- HTTP 1.1
- 오늘날 가장 많이 쓰는 버전, 파이프라인 연결, 캐시, 웹소캣 등 추가
- Persistent connections : 여러 요청을 합쳐 single connection을 사용하여 실행
- keep-alive : 클라이언트의 연결 요청을 처리한 후 바로 연결을 끊는것이 아니라, 연결을 끊지않고 일정시간 대기하는 시간
- HTTP 2.0
- Multiplexed Streams : 한 커넥션으로 동시에 여러개의 메세지를 주고 받을 수 있으며 response는 순서에 상관없이 stream으로 주고받는다.
- Stream Prioritization : 리소스간 우선순위를 설정해 클라이언트가 먼저 필요한 리소스부터 보내준다,
⇒ HTTP 1.0에서는 request, response마다 handshake 요청을 각각 보내야 한다. HTTP 1.1에서는 이미 연결되어 있는 TCP 연결을 재사용하여 handshake 과정이 많이 생략된다.
⇒ HTTP 1.1에서는 응답이 와야만 다음 전송을 보낼 수 있고, HTTP 2.0은 응답이 안와도 보낼 수 있다.
HTTP 1.0
- 기존 HTTP 0.9는 정보를 얻는 기능(GET)만 가능했다. 여기에 새로운 유틸리티들이 추가되어 개발된 것이 HTTP 1.0이다.
- 추가된 유틸리티들
- Header : HTTP 헤더를 도입해 유연하고 확장 가능한 데이터 전송이 가능해짐
- Versioning : HTTP 요청 시 버전을 명시적으로 알려줌
- Status code : 상태 코드를 통해 요청 처리상태 확인 가능
- Content-type : 일반 HTML 파일이 아닌 다른 형식의 문서도 전송할 수 있게됨(JSON 등)
- Method : GET 뿐만 아니라 POST, HEAD 제공
HTTP 1.1
- 오늘날 가장 많이 사용되는 HTTP 버전으로, 영구 및 파이프라인 연결, 압축/압축해제, 가상 호스팅, 캐시등이 추가되어 응답 속도가 빨라지고 대욕폭이 절약되는 등 성능 최적화 및 기능이 향상되었다.
- Host Header : Host 헤더를 통해 동일한 IP를 가리키는 도메인을 구분할 수 있다.
- Persistent connections
- HTTP 1.0에서는 request, response마다 새 연결을 했었음(3-way handshake)
- HTTP 1.1에선 여러 요청을 합쳐 single connection을 사용하여 실행
- 요청의 지역성을 이용하여 네트워크 혼잡/비용 감소, latency 감소
- 파이프라이닝
- 클라이언트와 서버간 요청과 응답의 효율성을 개선하기 위해 만들어진 개념
- 여러개의 HTTP Request 를 하나의 TCP/IP Packet 으로 연속적으로 Packing 해서 요청을 보낸다.
- keep-alive
- 클라이언트의 연결 요청을 처리한 후 바로 연결을 끊는것이 아니라, 연결을 끊지않고 일정시간 대기하는 시간
- HTTP 1.0도 keep-alive가 존재했지만 설계적인 측면에서 조금 문제가 있었고, HTTP 1.1에서 수정되어 현재 HTTP 1.1에서는 default로 keep-alive를 사용한다(Persistent connections를 통해).
- Method : PUT, PATCH, DELETE, OPTION 등이 추가됨
- websocket 사용 가능
HTTP 2.0
- HTTP 2.0은 HTTP 1.1 프로토콜을 계승한 동일 API이며, 성능 향상에 초점을 맞췄다.
- Multiplexed Streams
- 한 커넥션으로 동시에 여러개의 메세지를 주고 받을 수 있으며 response는 순서에 상관없이 stream으로 주고받는다.
- Keep-alive, 파이프라이닝을 개선함
- Stream Prioritization
- 리소스간 우선순위를 설정해 클라이언트가 먼저 필요한 리소스부터 보내준다.

Head of line blocking(HOLB)
- HOLB
- 패킷을 전송하고 싶은데, 이전 패킷을 전송하는데 지연이 발생해 패킷을 전송하지 못하는 상황
- HTTP/2에서의 HOLD, TCP에서의 HOLD가 있다.
- HTTP에서의 HOLD
- HTTP 1.1에서는 응답이 와야만 다음 전송을 보낼 수 있고, 이것이 HTTP1.1에서의 HOLD이다
- 하지만 HTTP 2.0은 병렬적으로 보낼 수 있기 때문에 HOLD가 발생하지 않는다.
- TCP에서의 HOLD
- TCP에서는 패킷을 전송 패킷이 손실되면 재전송하게된다.
- 재전송 발생 시 패킷의 순서가 역전되지 않도록 후속 패킷이 대기하게 된다. 이것이 TCP에서의 HOLD다.
Share article