Developing Myself Everyday
Published 2023. 5. 1. 17:46
REST API, Retrofit Android/Kotlin

 요즘 들어 개인 프로젝트를 진행한다고 블로그를 작성하는 것에 소홀했었다. 안드로이드 개발을 한다고 하면 반드시 마주치게 되는 것이 바로 REST API와 Retrofit이다. 안드로이드 스튜디오 자체에서 다 해결할 수 있다면 사용하지 않을 수 도 있겠지만 앵간하면 분명 위의 2가지와 마주치게 될 것이다. 좋은 개발자가 되기 위해서는 관련 개념에 대한 깊은 이해가 필요하기에 이 게시글을 통해 이해를 하고 넘어가고자 한다.

 

 

REST API


 REST API는 REpresentational State Transfer API의 약자로 HTTP 프로토콜을 사용해서 클라이언트와 서버 간 통신을 위한 아키텍처를 정의하는 웹 서비스 디자인 패턴이다.

 

 

HTTP & HTTPS

HTTP(HyperText Transfer Protocol) 이란? HTTP는 인터넷에서 웹 페이지를 전송하기 위해 사용되는 프로토콜이다. HTTP는 클라이언트와 서버 간에 데이터를 주고받을 수 있는 규칙을 정의하고 있다. 클라이

everyday-develop-myself.tistory.com

 결국은 클라이언트와 서버간 통신 방식중 하나라는 말이다. REST API를 사용하면 클라이언트는 HTTP 요청을 보내고 서버는 JSON, XML 등의 데이터 형식으로 응답을 보내는 방식으로 상호작용할 수 있다. 하지만 REST API를 이대로는 사용하기가 어렵다. 이를 도와주는 방식이 바로 Retrofit이다. RESTAPI와 Retrofit에 대해 자세히 알아보기 전에 REST에 대해서 알아보도록 하겠다.

 

 

REST란?

 어떤 자원에 대해 CRUD(Create, Read, Update Delete) 작업을 수행하기 위해 URI로 HTTP Method를 사용해 요청을 보내며, 요청을 위한 자원은 Representations으로 표현한다.

 

REST의 구성요소

 1. 자원 - URI로 표현되며, 클라이언트가 접근하고자 하는 데이터를 의미한다.

 2. HTTP Method -클라이언트가 자원에 대한 CRUD(Create, Read, Update Delete) 작업을 수행하기 위한 HTTP Method이다.

 3. Representations - 자원을 표현하는 데이터 형식으로, 클라이언트와 서버 간에 데이터를 주고받는 데 사용된다.

 4. Self-descriptive messages - 요청과 응답 메시지가 자체적으로 충분한 정보를 포함하고 있어 클라이언트가 메시지를 이해할 수 있도록 한다.

 5. HATEOAS - 클라이언트가 API에서 제공되는 자원 간 관계를 탐색하고 이를 통해 애플리케이션 상태를 변경할 수 있는 기능을 제공한다.

 

HATEOAS의 대한 자세한 설명은 아래의 링크에 있다.

 

REST API에서 HATEOAS란?

HATEOAS란? HATEOAS(Hypermedia as th engine of application state)는 클라이언트가 API에서 제공되는 자원 간 관계를 탐색하고 이를 통해 애플리케이션 상태를 변경할 수 있는 기능을 제공한다. 만약 REST API에서 H

everyday-develop-myself.tistory.com

 

 이런 REST의 특징을 기반으로 API를 구현한 것이 바로 REST API이다.

 REST API의 가장 큰 특징은 각 요청이 어떤 동작이나 정보를 위한 것인지를 그 요청의 모습 자체로 추론할 수 있다는 것이다. 그래서 우리가 만약 서버를 구축하고 PHP를 작성한다면 URI을 어디에 위치시키고 폴더명을 어떻게 해야하는지가 상당히 중요해진다.

 

 

 REST API에는 많은 규칙이 있다. 그 규칙은 다음과 같다.

 

  1. URI는 정보의 자원을 표현해야 한다.

  • 리소스의 식별자는 URI로 나타내며, 각 리소스마다 고유한 URI를 갖는다.
  • 리소스는 단순한 자원이 아니라, 복합적인 개체(객체)이므로 URI에는 동사보다는 명사를 사용하는 것이 좋다.

  2. URI의 계층 구조는 클라이언트와 서버 간에 의미있는 관계를 나타내어야 한다.

  • 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현해야 한다.
  • HTTP Method는 GET, POST, PUT, DELETE 외에도 다양한 Method가 존재하지만, REST API에서는 이 중 가장 일반적인 4개를 사용한다.
  • URI는 자원의 위치를 나타내는 것이므로, 자원에 대한 행위는 HTTP Method로 나타내어야 한다.
  • GET은 리소스를 조회하는 용도, POST는 리소스를 생성하는 용도, PUT은 리소스를 갱신하는 용도, DELETE는 리소스를 삭제하는 용도로 사용한다.

  3. 메시지는 스스로를 설명해야 한다.

  • REST API에서는 HTTP Header와 Body를 포함한 모든 메시지가 스스로를 설명해야한다.
  • Header는 메시지에 대한 추가적인 정보를 담으며, Body는 실제 전송할 데이터를 포함한다.
  • Header는 메시지의 전송에 필요한 정보를 제공하며, Body는 리소스의 상태 정보나 새로운 리소스 생성 시 전송할 데이터를 담는다.

   4.  API 버전 관리를 위해 URI에 버전 정보를 포함할 수 있다.

  • API 버전 관리를 위해 URI에 버전 정보를 포함하는 것이 좋다.
  • URI의 가장 앞부분에 버전 정보를 포함하여, API의 버전 관리를 쉽게 할 수 있다.

  5. Hypermedia를 활용한다(HATEOAS).

  • RESTful한 API를 만들기 위해서는, Hypermedia를 활용하여 API의 Discoverability를 높여야 한다.
  • 즉, API의 각 요청마다 해당 리소스와 연관된 다른 리소스로의 링크를 포함하여, 클라이언트가 다음에 어떤 동작을 수행할 수 있는지에 대한 정보를 함께 전달한다.

   6.  상태 정보는 Stateless Server에서 관리한다.

  • REST API에서는 서버가 상태 정보를 관리하지 않다. 대신, 클라이언트의 모든 요청에 대한 상태 정보를 포함하고 있어야 한다.
  • 클라이언트가 요청을 보낼 때 필요한 모든 정보는 요청 메시지 안에 포함되어 있어야 한다.
  • 서버는 요청에 대한 적절한 응답만 제공하며, 클라이언트가 다음 요청에 필요한 정보를 모두 갖추고 있어야 한다.

   7.  캐시 처리 가능(Cacheable)해야 한다.

  • REST API에서는 캐시를 사용하여 응답 속도를 높일 수 있다.
  • 클라이언트가 이전에 받았던 응답을 캐시에 저장하여, 다음에 같은 요청을 보낼 때 캐시에서 가져올 수 있다.
  • 이를 위해 서버는 응답에 캐싱 가능 여부를 나타내는 정보를 포함해야 한다.

   8. 클라이언트-서버 구조

  • REST API는 클라이언트-서버 구조를 따른다.
  • 클라이언트는 서버로 요청을 보내고, 서버는 이에 대한 응답을 반환한다.
  • 이 구조는 클라이언트와 서버를 각각 독립적으로 개발할 수 있도록 해주며, 서로 간의 의존성을 줄일 수 있다.

   9. 계층화(Layered System)

  • REST API는 계층화된 시스템을 구성할 수 있다.
  • 클라이언트는 서버와 직접 통신하지 않고, 중간에 프록시 서버 등 다른 서버를 거쳐 요청을 보낼 수 있다.
  • 이러한 계층화된 시스템은 확장성과 보안성을 높일 수 있다.

 

 이렇게 많은 규칙을 따르면 클라이언트와 서버 간의 상호작용을 일관성 있게 유지할 수 있으며, API의 가독성과 유지보수성이 높아진다. 이런 규칙을 엄격하게 준수하는 API를 RESTful API라고 한다.

 

 

Retrofit과 OkHttp


 Retrofit을 알기 전에 우선적으로 OkHttp에 대해 알아야 한다. OkHttp는 HTTP 클라이언트 라이브러리로, 안드로이드 애플리케이션에서 HTTP 요청을 처리하기 위해 사용된다. OkHttp는 매우 간단하면서도 안정적인 라이브러리로, 서버와의 통신에서 많이 사용된다. 또한 OkHttp는 HTTP/2, SPDY, 웹 소켓 등 다양한 프로토콜을 지원하며, 인터셉터(interceptor)를 통해 요청과 응답을 가로채서 처리할 수 있다. 이를 통해 캐싱, 로깅, 인증 등 다양한 작업을 수행할 수 있다.

 Retrofit은 바로 위에서 설명한 OkHttp를 기반으로한 RESTful API 클라이언트 라이브러리이다. Retrofit은 REST API를 호출하기 위한 인터페이스를 정의하고, 이를 바탕으로 실제로 요청을 처리하는 코드를 생성한다. 이렇게 생성된 코드는 OkHttp를 사용하여 요청을 처리하며, 이를 통해 REST API와 통신하는 작업을 쉽게 구현할 수 있다.

 Retrofit은 REST API를 구현할 때 많이 사용되며, 이를 사용하면 다음과 같은 장점이 있다.

  • 코드의 간결성: Retrofit은 REST API 인터페이스를 정의하는 코드를 간결하게 작성할 수 있습니다. 이를 통해 코드의 가독성을 높이고, 유지보수를 쉽게 할 수 있다.
  • 유연성: Retrofit은 다양한 커스텀 요청과 응답 처리를 지원합니다. 이를 통해 REST API에 대한 요청과 응답을 다양하게 처리할 수 있다.
  • OkHttp와의 호환성: Retrofit은 OkHttp와 함께 사용할 수 있습니다. 이를 통해 OkHttp의 다양한 기능과 Retrofit의 간결함을 함께 사용할 수 있다.
  • 스레드 안전성: Retrofit은 스레드 안전성을 보장합니다. 이를 통해 멀티스레드 환경에서 안정적인 REST API 호출을 구현할 수 있다.

따라서, OkHttp와 Retrofit은 안드로이드 애플리케이션에서 네트워크 통신을 쉽게 구현하기 위해 필요한 라이브러리이다.

 

 

Retrofit을 사용하여 REST API와 통신하는 예제


 우선, Retrofit을 사용하기 위해서는 Retrofit 라이브러리를 build.gradle 파일에 추가해야 한다.

 

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}

 

 위의 의존성을 추가한 후, 아래와 같이 Retrofit 인터페이스를 정의한다.

 

interface MyApi {
    @GET("posts")
    fun getPosts(): Call<List<Post>>
}

 

 다음으로, Retrofit 인스턴스를 생성한다.

 

val retrofit = Retrofit.Builder()
    .baseUrl("https://jsonplaceholder.typicode.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

 

 위의 코드에서는 baseUrl() 함수로 서버의 기본 URL을 설정하고, addConverterFactory() 함수로 데이터 파싱을 위한 Gson 라이브러리를 추가한다. 

 마지막으로, Retrofit 인터페이스를 구현한 객체를 생성하고, 해당 객체를 사용하여 REST API를 호출하면 된다.

 

val api = retrofit.create(MyApi::class.java)

api.getPosts().enqueue(object : Callback<List<Post>> {
    override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) {
        if (response.isSuccessful) {
            val posts = response.body()
            // TODO: 처리 로직 작성
        }
    }

    override fun onFailure(call: Call<List<Post>>, t: Throwable) {
        // TODO: 에러 처리 로직 작성
    }
})

 

 위의 코드에서는 Retrofit 인터페이스를 구현한 객체를 생성하고, enqueue() 함수를 통해 비동기식으로 REST API를 호출한다. 호출 결과는 Callback 인터페이스를 통해 처리한다.

 onResponse() 함수에서는 HTTP 요청이 성공한 경우 response.body() 함수를 통해 요청 결과를 받아 처리할 수 있다. onFailue() 함수에서는 HTTP 요청이 실패한 경우에 에러 처리를 하는 로직을 작성하면 된다.

 

 

 

이렇게 REST API와 Retrofit에 대해 생각보다 길게 알아보았다. 어떻게 통신이 진행되는지에 대한 이해가 존재한다면, 위의 게시글을 이해하는 것은 어렵지 않을 것이라고 생각한다.

 

 

 

 

 

 

 

 

 

 

 

Reference

 

REST란? REST API 와 RESTful API의 차이점

참고 REST(REpresentational State Transfer)란? REST의 정의 "REpresentational State Transfer" 의 약자로, 자원을 이름(자원의 표현)으로 구분해 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미합니다. 즉, 자원(

dev-coco.tistory.com

 

'Android > Kotlin' 카테고리의 다른 글

Enum Class  (0) 2023.05.26
Abstract Class & Interface  (0) 2023.05.25
변수 캡슐화하기 (Encapsulate Variable)  (0) 2023.05.12
REST API에서 HATEOAS란?  (0) 2023.05.01
Retrofit 이란?  (0) 2023.04.03
profile

Developing Myself Everyday

@배준형

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!