REST API

Jeonghak Cho·2021년 6월 7일
0

Microservice

목록 보기
1/1
# 아키텍처 컴포넌트 ![](https://velog.velcdn.com/images%2Fmanarc%2Fpost%2F2d803d70-a78e-41b3-bb08-2ad71685a4f2%2Fimage.png)

UI

사용자가 브라우저에서 접하는 화면입니다. 사용자의 행위에 의해 이벤트가 발생하고 서버로 요청이 들어갑니다. 전통적인 방식에서는 서버에서 렌더링 된 HTML을 WAS로 부터 내려 받아 화면을 구성한 반면, SPA에서는 클라이언트에서 렌더링 한 후 직접 API를 호출합니다.

웹애플리케이션

웹자원 (HTML, Javascript, CSS 등)이 위치합니다. 서버 렌더링의 경우, JSP등을 이용하여 REST API 호출한 후 백엔드로부터 전달받은 JSON 데이타를 이용해서 화면을 구성합니다. 클라이언트 렌더링 방식에서는 웹애플리케이션 서버 내부 파일 시스템 대신 AWS Bucket, BitBucket등의 오브젝트 저장소를 이용해서 Static Website를 구성할 수 있습니다. 이 경우 버킷의 도메인을 통해 index.html을 불러옵니다.

API 게이트웨이

API 게이트웨이는 시스템의 유일한 진입점을 제공하는 서버입니다. 객체 지향 디자인의 Facade Pattern 처럼 API Gateway는 내부의 시스템 아키텍처를 은닉하고 개별 클라이언트에게 적절하게 가공된 API 를 노출합니다.  더하여, 인증처리, 모니터링, 로드밸런싱, 캐싱 등의 기능을 제공합니다.  API 게이트웨이는 리버스 프록시 처럼 작동하여, 클라이언트로 부터 요청되는 API 를 모두 받아들이면서 클라이언트로 결과 값을 전송합니다. 여러 요청을 합쳐서 (Aggregation) 한번에 보내줄 수 있습니다.

컨트롤러/서비스/DAO

Spring boot의 애노테이션을 이용해서 외부에서 들어오는 요청을 백엔드의 서비스와 연결하는 역할을 컨트롤러가 합니다. 클라이언트 요청의 헤더 정보인 Contents-Type 을 이용해서 수신 되는 데이타의 타입을 지정합니다.

Spring Boot 애노테이션

@Controller 애노테이션은 결과 값에 해당하는 이름에 매칭되는 View를 찾아 주며, @RestController 는 JSON, XML 형태로 HTTP response 를 직접 호출한 곳으로 보내줍니다.

@Service, @Repository 는 @Component 애노테이션에 대한 논리적인 구분으로 서비스 레이어와 퍼시스턴스 레이어를 구별하기 위해 사용합니다.

롬복을 사용할 경우 @Data를 사용해서 엔티티 오브젝트의 getter/setter를 작성하는 수고를 들 수 있습니다.

REST 의미

Representational State Transfer의 약어로 웹 서비스를 설계하는 아키텍처적인 접근 방법입니다. 

REST 는 URI를 통해 제어할 자원을 명시하고 HTTP 메서드 (GET, POST, PUT, DELETE)를 통해 해당 자원을 제어하는 명령을 내리는 방식입니다.

마이크로 서비스는 하나의 엔드포인트를 가지는 것을 원칙으로 하고 하나의 역할 만을 가집니다. 각각의 역할별 마이크로 서비스가 뭉쳐서 육각형 벌집 모양으로 뭉친 폴리글랏 아키텍처를 형성합니다.  클라이언트는 엔드포인트를 달리 가지는 마이크로 서비스를 RESTful API 호출을 통해 서비스를 받습니다. 

기존 방식대로 라면 CRUD에 해당하는 URI를 모두 달리 사용해야 했으나 RESTful 서비스에서는 URI는 동일하게 사용하고 메소드를 달리하여 사용할 수 있습니다.

아래 처럼 Spring boot 컨트롤러에서 동일한 URI 에 대해 애노테이션을 사용한 각 메소드 매핑으로 구분이 가능합니다.

    @GetMapping(path = "/users/{name:[a-z]+}",consumes = "application/json", produces ="application/json")
    public String selectUser(@PathVariable String name) {
    	 
    	//some select operation
    	return "user " + name + " was selected!";
    }
    
    @PostMapping(path = "/users/{name:[a-z]+}",consumes = "application/json", produces ="application/json")
    public String updateUser(@PathVariable String name) {
    	//some update operation
    	
    	return "user " + name + " was updated!";
    }
    
    @PutMapping(path = "/users/{name:[a-z]+}",consumes = "application/json", produces ="application/json")
    public String insertUser(@PathVariable String name) {
    	 
    	//some deletion operation
    	
    	return "user " + name + " was insert!";
    }
    
    @DeleteMapping(path = "/users/{name:[a-z]+}",consumes = "application/json", produces ="application/json")
    public String deleteUser(@PathVariable String name) {
    	 
    	//some deletion operation
    	
    	return "user " + name + " was deleted!";
    }

호출 시 메소드를 변경하여 동일한 URI 호출을 합니다.

C:\Users\alex>curl -X DELETE -H "Content-Type: application/json" http://localhost:8888/users/alex
user alex was deleted!
C:\Users\alex>curl -X PUT -H "Content-Type: application/json" http://localhost:8888/users/alex
user alex was insert!

URL 과 URI 의 차이점

  • URL ( Uniform Resource Locator )
    URL은 인터넷 상 자원이 어디 있는지를 알려주기 위한 규약입니다. 

  • URI ( Uniform Resource Identifier )
    URI는 인터넷에 있는 자원을 나타내는 유일한 주소입니다.

  • URN (Uniform Resource Name)
    리소스의 위치가 아닌 유일한 이름을 사용

http://example.com/ex.pdf?docid=100 는 http://example.com/ex.pdf 가 URL 이고  http://example.com/ex.pdf?docid=100 가 URI 입니다.

http://example.com/ex.pdf?docid=100 와 http://example.com/ex.pdf?docid=200 은 동일한 URL 을 가지나 URI 가 다른 경우 입니다.

URN은 일반적으로 urn: 으로 시작하고 리소스를 식별하는 고유명을 나타내지만 위치정보는 꼭 필요치 않습니다. urn:isbn:1234

접점(엔드포인트)와 자원(리소스)의 차이점

  • 엔드포인트
    요청을 만들기 위해 사용하는 URL 에 초점을 둡니다.

  • 리소스
    요청에 의해 반환되는 데이타에 초점을 둡니다.

동일한 리소스는 복수개의 다른 엔드포인트에 의해 접근될 수 있습니다.

예)  다른 엔트포인트가 동일한 자원에 접근하는 예제입니다. 1번 사용자는 버전명, 그룹명이 표기되어도 동일한 사용자입니다.

/api/users/1
/api/v1/users/1
/api/groups/1/users/1

엔드포인트는 Query 문자열에 따라 다른 리소스를 반환할 수 있습니다. 

예) 아래의 URL은 동일한 엔드포인트(/api/users)를 가지나 검색/필터/정렬 목적으로 붙는 쿼리 문자열에 따라 반환하는 리소스가 달라집니다.

/api/users
/api/users?sort=name-asc
/api/users?name=mina
/api/users?location=jukjeon

RESTful 웹서비스는 REST 형태의 웹서비스이며 다음의 특징을 가집니다.

  • 기본 URL 을 가집니다. 예) http://example.com/resources/
  • 웹서비스로 지원되는 데이타의 Media type ( JSON, XML, YAML 등) 을 가집니다.
  • HTTP 메소드 (POST, GET, PUT, DELETE) 를 사용하여 CRUD 오퍼레이션이 가능합니다.
  • 하이퍼텍스트 기반입니다.

REST의 구성요소

  • 자원 ( Resource ) - URI가 가르키는 서버의 자원
  • 행위( Verb) - GET, POST, PUT, DELETE
  • 표현 (Representation)

어떤 리소스의 특정 시점의 상태를 반영하는 정보로 representation data와 representation metadata로 구성됩니다.

예를 들어 https://example.com/greeting 이 가르키는 자원의 representation 은 영어 사용자를 위한 "hello", 한글 사용자를 위한 "안녕" 이 될수 있습니다.

여러 representation 중 선택 대상은 클라이언트와 서버간의 내용 협상을 통해 선택되며 선택의 주체는 협상 방법에 따라 다릅니다. 

클라이언트가 GET 요청에 "Accept-Language: ko" 헤더를 포함시켜 한국어를 선호할 경우 서버는 가장 적절한 "안녕"을 선택하는 식입니다.

엔드 포인트 명명법

  • URI 리소스는  명사형
    예) /users/{userid} (O) , /getUser (X)

  • 리소스 집합은 복수형으로 표현
    예) GET /users/123

  • 리소스명은 소문자, 언더스코어(_) 대신 하이픈(-) 사용
    예) /users/{id}/pending-orders ( O) , /users/{id}/Pending_Orders

  • 파일 확장자는 URI에 미포함Content-Type헤더를 통해 미디어 타입이 결정되니 불필요

Versioning

버전을 관리하는 것은 API 설계의 매우 중요한 부분입니다. 버전을 통해 개발자는 새로운 업데이트가 롤 아웃될때 클라이언트의 애플리케이션의 장애 없이 API를 개선하는 일이 가능하게 됩니다.

일반적으로 사용되는 버전에 대한 전략은 다음과 같습니다. 

  • 커스텀 헤더에 버전 표기
    “Accepts-version: 1.0”

컨텐츠 협상에 의한 버전 표기
“Accept: application/vnd.xm.device+json; version=1”

HTTP 상태 코드

2xx 성공

  • 200 OK : 서비스가 생성 및 변경 작업 후 리소스를 다시 반환하고 싶지 않을 경우, 성공적인 오퍼레이션 후 반환. 

  • 201 Create: POST 요청에 의해 성공적으로 리소스 생성이 되었을 때 반환되는 응답

3xx 리다이렉션

 304 Not Modified : HTTP 캐싱 헤더가 구현될 때 사용됨

4xx 클라이언트 오류

  • 400 Bad Request : HTTP 요청 바디가 파싱에 실패할때 발생

  • 401 Unauthorized : 인증 실패

  • 403 Forbidden : 사용자가 인증 정보가 맞아도 특정 액션 수행 권한이 없으면 발생

  • 404 Not Found : 요청된 리소스가 서버에서 사용될 수 없을 때 발생

5xx 서버 오류

  서버 장애나 인프라 이슈가 있을 때 발생

API 문서화

JSON 형태의 문서를 업데이트 하면 웹화면에 변경 사항을 바로 반영해서 보여줍니다. Plug-in 사용 시 구현된 소스의 Controller 영역에서 Annotation 기반으로 Swagger 문서를 뽑아낼 수 있습니다.

만들어진 Swagger 문서는 API 게이트웨어에서 import가 가능합니다.

https://swagger.io/tools/swagger-editor/

profile
함께하는자

0개의 댓글