서버 개발자님 API 하나만 만들어 주세요~
네트워크 통신에서 많이 사용하는 REST API 많이 들어봤는데.. 이게 뭐지
REST API란 REST 아키텍처의 제약 조건을 준수하는 애플리케이션 프로그래밍 인터페이스를 뜻합니다. 또한 REST는 Representational State Transfer의 줄임말입니다.
- 서버와 클라이언트 구조
- Socket 통신과 다르게 양방향이 아닌 단방향 통신
- Request와 Response로 이루어짐
- Get, Post, Put, Delete 등의 메소드 사용
간단하게 정리하면 클라이언트가 서버에 "~해줘(Request)"라고 보내면
서버는 너가 원하는거 했으니까 "받아~(Response)"라고 다시 보내고
클라이언트는 그 Response를 받는 구조인 것이죠.
그럼 REST API에 대해 알았으니 어떻게 사용하는지 알아보면
HttpURLConnection, HttpsURLConnection
OkHttp
Retrofit
이런 클래스나 라이브러리를 사용하여 통신을 구현합니다.
HttpURLConnection의 사용 방법을 알아보면
우선 안드로이드 스레드 글을 보면 안드로이드에서 네트워크 통신 작업처럼 오래 걸리는 작업은 Worker Thread에서 처리를 해야 한다고 했습니다.
그래서 보통 AsyncTask를 사용하여 구현하는데 AsyncTask는 deprecated 되었죠..
그래서 예제에서는 RxJava를 사용하여 비동기 처리를 하였습니다.
다음은 사용자의 이름, 전화번호, 주소를 서버로 request를 보내는 예제입니다.
public class UserInfoTask {
private Disposable userInfoTask;
private final String USER_AGENT = "Mozilla/5.0";
private String name;
private String phone;
private String address;
private String response;
public AutoActionsTask(String name, String phone, String address) {
this.name = name;
this.phone = phone;
this.address = address;
}
public void sendUserInfo() {
String urlString = (request를 보낼 서버의 url);
userInfoTask = Observable.fromCallable(()->{
HttpURLConnection conn;
URL url = new URL(urlString);
// url 연결
conn = (HttpURLConnection) url.openConnection();
// 서버 접속시 연결 시간
conn.setConnectTimeout(10000);
// Read시 연결 시간
conn.setReadTimeout(100000);
// 요청방식 선택
conn.setRequestMethod("POST");
// 타입설정
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
// User-Agent 값 설정
conn.setRequestProperty("User-Agent", USER_AGENT);
// OutputStream으로 Post 데이터를 넘겨주겠다는 옵션
conn.setDoOutput(true);
// InputStream으로 서버로 부터 응답을 받겠다는 옵션
conn.setDoInput(true);
// 서버로 전달할 Json객체 생성
JSONObject json = new JSONObject();
// Json객체에 유저의 name, phone, address 값 세팅
// Json의 파라미터는 Key, Value 형식
json.put("userName", name);
json.put("userPhone", phone);
json.put("userAddress", address);
// Request Body에 데이터를 담기위한 OutputStream 객체 생성
OutputStream outputStream;
outputStream = conn.getOutputStream();
outputStream.write(json.toString().getBytes());
outputStream.flush();
// 실제 서버로 Request 요청 하는 부분 (응답 코드를 받음, 200은 성공, 나머지 에러)
int response = conn.getResponseCode();
String responseMessage = conn.getResponseMessage();
response = String.valueOf(responseCode);
// 접속해지
conn.disconnect();
return response;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
userInfoTask.dispose();
}, throwable -> throwable.printStackTrace());
}
}
위와 같은 형태로 HttpURLConnection클래스를 사용하여 비동기 Rest API 통신이 가능합니다.
OkHttp는 REST API, HTTP 통신을 간편하게 구현할 수 있도록 다양한 기능을 제공해주는 Java 라이브러리입니다. "Square"라는 회사가 만든 OkHttp 라이브러리는 다음에 나올 Retrofit 이라는 라이브러리의 베이스가 되는 라이브러리입니다.
사용 방법은 먼저 build.grdle의 Module단에 선언합니다.
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
이후 OkHttp 클래스를 하나 만들겠습니다.
public class HttpConnection {
private OkHttpClient okClient;
private static HttpConnection instance = new HttpConnection();
public static HttpConnection getInstance() {
return instance;
}
private HttpConnection(){
this.client = new OkHttpClient();
}
// 웹서버로 요청
public void requestWebServer(String parameter1, String parameter2, Callback callback) {
RequestBody body = new FormBody.Builder()
.add("parameter1", parameter1)
.add("parameter2", parameter2)
.build();
Request request = new Request.Builder()
.url("전송할 url")
.post(body)
.build();
okClient.newCall(request).enqueue(callback);
}
}
여기서 enqueue는 비동기
동기식은 execute를 사용합니다.
이후
public class MainActivity extends AppCompatActivity {
private HttpConnection conn = HttpConnection.getInstance();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
sendData(); // 웹 서버로 데이터 전송
}
/** 웹 서버로 데이터 전송 */
private void sendData() {
// 네트워크 통신하는 작업은 무조건 작업스레드를 생성해서 호출 해줄 것!!
new Thread() {
public void run() {
// 파라미터 2개와 미리정의해논 콜백함수를 매개변수로 전달하여 호출
httpConn.requestWebServer("데이터1","데이터2", callback);
}
}.start();;
}
private final Callback callback = new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "오류:"+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String body = response.body().string();
Log.d(TAG, "응답한 Body:"+body);
}
};
}
위와 같은 형태로 액티비티에서 사용이 가능합니다.
Retrofit은 위에서 나온 "Square"라는 회사가 만든 OkHttp 라이브러리의 상위 구현체입니다.
Retrofit은 OkHttp를 네트워크 계층으로 활용하고 그 위에 구축 되었습니다.
일단 Retrofit은 3가지 구성요소가 있습니다.
사용 방법으로는 먼저 OkHttp처럼 모듈단에 선언해줍니다.
// Retrofit 라이브러리
implementation 'com.squareup.retrofit2:retrofit:2.6.4'
// Gson 변환기 라이브러리
implementation 'com.squareup.retrofit2:converter-gson:2.6.4'
// Scalars 변환기 라이브러리
implementation 'com.squareup.retrofit2:converter-scalars:2.6.4'
이후 먼저 모델을 생성해줍니다.
public class Result {
@SerializedName("id")
private int id;
@SerializedName("name")
private int name;
@SerializedName("body")
private String body;
// toString()을 Override 해주지 않으면 객체 주소값을 출력함
@Override
public String toString() {
return "Result{" +
"userId=" + userId +
", id=" + id +
", name='" + name + '\'' +
", body='" + body + '\'' +
'}';
}
}
이후 사용할 메소드를 선언한 인터페이스를 정의 해줍니다.
public interface RetrofitService {
@GET("posts/{info}") // url을 제외한 End Point
Call<Result> getResults(@Path("info") String body); // get방식
@POST("posts/post")
Call<Result> postInfo(@Header("token") String token, @Body String body); // post방식
}
이후 Retrofit 인스턴스를 생성해주고
// OkHttp 클라이언트 생성
private static OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
// Retrofit 인스턴스 생성 (싱글톤 방식)
public static Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SettingHandler.oSetting.APIServerUrl)
.client(okHttpClient) // 위에 생성한 클라이언트 사용
.addConverterFactory(GsonConverterFactory.create())
.build();
Retrofit 인스턴스를 생성해주고
클래스 내에서 사용하려면
RetrofitService retrofitService = RetrofitServiceeBuilder.retrofit.create(RetrofitService.class);
// 사용할 메소드 선언
Call<Result> call = retrofitService.getResults("1");
call.enqueue(new Callback<Device>() { // 비동기 실행
@Override
public void onResponse(Call<Result> call, Response<Result> response) {
if (response.isSuccessful()) { // 성공여부에 따라 작업 처리
Result result = response.body();
System.out.println("성공")
} else {
System.out.println("실패")
}
}
@Override
public void onFailure(Call<Device> call, Throwable t) {
System.out.println("통신 실패" + t.getMessage) // 예외 발생
}
});
위와 같은 방식으로 클래스 내에서 사용할 수 있습니다.
역시 배우기만 한다면 가장 최근에 나온 Retrofit이 가장 편하다고 느껴집니다.