본문 바로가기

안드로이드/안드로이드 개인공부

[안드로이드 개인공부] Retrofit 사용방법

사용자가 URL을 브라우저 주소창에 작성하여 엔터를 누르면 원하는 페이지가 나온다.

특정 웹페이지를 사용자 웹 브라우저에게 보여주기 위해 내부적인 처리들을 하는 것이다.

 

그 내부적인 처리에서, 클라이언트가 서버에게 웹페이지를 보여달라고 하는 것을 요청이라고 하며,

그에 대한 서버의 대답을 응답이라고 한다.

 

클라이언트가 서버로 요청하기 위해서 HTTP패킷을 사용한다.

HTTP패킷은 크게 헤더와 바디로 나뉘어진다.

 

헤더에는 메소드방식, 클라이언틔 정보, 브라우저 정보, 접속할 URL등 정보를 담을 수 있다.

바디는 보통 비어 있는데, 특정 데이터를 담아서 서버에게 요청이 가능하다.

 

여기서 GET과 POST방식으로 나눌 수가 있다.

 

<간단히 GET과 POST의 차이는?> 

 

- GET의 경우

클라이언트가 입력한  Query의 이름과 값이 결합되어 스트링 형태로 서버에 전달한다.

DB에 추가로 정보를 처리하지 않고, 저장된 Data를 단순히 요청하는 정도로 많이 사용되어진다.

 

- POST는 클라이언트와 서버 간에 인코딩하여 서버로 전송하게 됩니다. 즉, 헤더를 통해 요청이 전송되는 방식이다.

주로 DB 추가로 서버에서 갱신 작업할 때, 서버에서 정보가 가공되어 응답하는 경우에 사용하며,

Query가 Body안에 들어가 있어서 보안에 유리한 점이 있다.

 

<Body의 데이터를 설명하는 Content-Type 헤더 필드는?>

컨텐츠 타입으로 여러개가 있지만 대표적으로 아래와 같다.

 

1. application/x-www-form-urlencoded
2. text/plain
3. multipart/form-data

 

1번타입의 경우 GET방식과 마찬가지로 Body에 key와 value쌍으로 데이터를 넣는다.

2번타입의 경우 Body에 단순히 txt를 넣는다.

3번타입의 경우 파일 전송을 할 경우 많이 사용한다.

 

안드로이드에서 HTTP통신을 하기 위해서 다양한 라이브러리가 있다.

여기서는 Retrofit라이브러리를 사용하는 방법에 대해서 간단하게 소개하겠다.

참고자료는 https://square.github.io/retrofit/ 이다.

 

<Gradle 추가>

 

compile 'com.squareup.retrofit2:retrofit:2.5.0'

 

Retrofit은 Java 7이상,  Android 2.3 이상에서만 사용가능하다.

Retrofit은 HTTP API를 자바 인터페이스 형태로 사용할 수 있다.

 

public interface GitHubService {
  @GET("/users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

여기서 @Path로 넘어온 user값이 @GET에 있는 user안으로 들어가게 된다.

 

다음으로 Retrofit 클래스로 GitHubService 인터페이스를 구현하여 생성한다.

 

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .build();

GitHubService service = retrofit.create(GitHubService.class);

 

baseUrl에 통신한 Url을 적어주게 되고, 빌드한다.

생성한 Retrofit 객체에 HTTP API 자바 인터페이스 값을 넣고 GitHubService 인터페이스를 생성한다.

 

Call은 GitHubService를 통하여 동기 또는 비동기하는 HTTP 요청을 원격 웹서버로 보낼 수가 있다.

 

Call<List<Repo>> repos = service.listRepos("octocat");

 

이로써 https://api.github.com/users/octocat/repos에 요청하게 된다.

 

* HTTP 요청은 어노테이션을 사용하여 명시하며, URL 파라미터 치환과 쿼리 파라미터가 지원된다.

* 객체를 요청 body로 변환하고(JSON, protocol buffers), 멀티파트 요청 body와 파일 업로드 또한 가능하다..

 

다음은 인터페이스의 어노테이션과 메소드 매개변수들을 어떻게 다룰지 알아보겠습니다.

 

<요청메소드의 종류>

모든 메소드들은 반드시 상대 URL과 요청 메소드를 명시하는 어노테이션을 가지고 있어야한다.

기본적으로 제공하는 어노테이션은  GET, POST, PUT, DELETE, HAED 5개가 있다.

자세한 내용은 https://spring.io/understanding/REST를 참고하면 도움이 될 것이다.

 

<GET 요청 메소드 사용방법>

 

@GET("/users/list")
@GET("/users/list?sort=desc")

GET에는 이렇게 정적 쿼리 인자를 명시할 수도 있다.

 

@GET("/group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

 

동적으로 부분 치환도 가능하고, 이는 메소드의 매개변수로 변경이 가능하다.

부분 치환은 영문/숫자로 이루어진 문자열을 { }로 감싸 정의해준다.

반드시 이에 대응하는 @Path 를 메소드 매개변수에 명시해주어야 한다.

 

@GET("/group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

 

쿼리 매개변수도 명시가 가능하다.

위의 경우 https://api.github.com/group/id값/users?sort = sort값이 된다.

 

@GET("/group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

보다 동적이고, 다양한 쿼리 매개변수들은 Map으로도 사용할 수가 있다.

 

<POST 요청 메소드 사용방법>

 

@POST("/users/new")
Call<User> createUser(@Body User user);

HTTP 요청 본문에 객체를 @Body 어노테이션을 통해 명시한다.

이러한 객체들은 Retrofit 인스턴스에 추가된 Converter에 따라서 변환된다.

만약에 해당 타입에 맞는 컨버터가 추가되어 있지 않다면, RequestBody를 사용해야한다.

 

<FormUrlEncoded 와 Multipart 요청 메소드 사용방법>

Post방식은 GET

 

@FormUrlEncoded
@POST("/user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

 

각 key-value pair구조이므로, @Field("first_name") String first 에서 "first_name" key값이 되며, 넘어온 변수 first의 값value의 값이 된다.

 

@Multipart
@PUT("/user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

각 파트들은 @Part로 누눌수가 있으며, Retrofit 컨버터나, ReqeustBody를 통하여 직렬화(Serialization) 가능한 객체를 사용할 수 있다.

 

<Header 다루기>

 

@Headers("Cache-Control: max-age=640000")
@GET("/widget/list")
Call<List<Widget>> widgetList();

 

정적 헤더들은 @Headers 어노테이션을 통해 명시할 수 있다.

 

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("/users/{username}")
Call<User> getUser(@Path("username") String username);

 

참고할 점은, 헤더들의 이름에 기준하여 각각의 값을 덮어씌우지 않는다. 동일한 이름의 헤더를 추가한다면 모든 헤더들은 동일한 이름으로 모두 요청에 추가된다. 

 

@GET("/user")
Call<User> getUser(@Header("Authorization") String authorization)

 

동적인 헤더들은 @Header 어노테이션을 통해 명시가 가능하다. 만약에 값이 null값이 들어온다면, 해당 헤더는 추가되지 않는다.