HTTP, REST API

choko's avatar
Jun 29, 2024
HTTP, REST API
 

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가지로 요약할 수 있습니다.
  1.  URI는 정보의 자원을 표현해야 한다
  1. 자원에 대한 행위는 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

 
notion image

start line

  • Request
    • GET /test.html HTTP/1.1 [HTTP Method] [Request target] [HTTP version]
    • http method (Post, Get 등)
    • Request target (URL)
    • HTTP Version (1.0, 1.1, 2.0 등)
 
  • Response
    • HTTP/1.1 200 OK [HTTP version] [Status Code] [Status Text]
    • Status Code
    • Status Text
    • HTTP Version
 
 

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개 파트로 나눌 수 있다.-
notion image
  • 여기서 Message Body에 들어가는 타입을 HTTP Header에 명시할 수 있는데, Content Type 필드를 이용한다.
  • ex) 텍스트 타입은 text/html, file 타입은 multipart/form-data, json 타입은 application/json
 
  • URL
  1. application/json : RestFul API를 사용하게 되며 request를 날릴 때 대부분 json을 많이 사용하게 됨에 따라 자연스럽게 사용이 많이 사용, {key:value} 형태로 전송
  1. application/x-www-form-urlencoded는 html의 form의 기본 Content-Type, 보내는 데이터를 URL 인코딩이라고 부르는 방식으로 인코딩 후 보냄, key=value&key=value 형태로 전송
  1. mutipart/form-data : 파일 업로드의 경우 이 방식을 사용해야 됨. 메세지가 문자인지, 파일인지를 multipart의 파트별로 분리하여 개별 파일을 분리하여 전송
    1. 따라서 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") }
       
      • URI
        • URI는 특정 리소스를 식별하는 통합 자원 식별자(Uniform Resource Identifier)를 의미
        • notion image
        • URI는 그 자체로, 이름+주소(Host+Path)이거나 이름이다.
        • URL은 Scheme이 붙어, URI에 프로토콜이 결합된 형태이다.
 
 

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]
  1. 우선 변수 이름은 — superHeroes이다.
  1. members 프로퍼티에 접근하려면, ["members"]를 입력한다.
  1. members는 객체로 구성된 배열입니다. 두 번째 객체에 접근할 것이므로 [1]를 입력한다.
  1. 이 객체에서 powers 프로퍼티에 접근하려면 ["powers"]를 입력한다.
  1. 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
      • 리소스간 우선순위를 설정해 클라이언트가 먼저 필요한 리소스부터 보내준다.
       
      notion image
       
 

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

Tom의 TIL 정리방