본문 바로가기

개발/Spring

외부 api 연동하기(retrofit2, form urlencoded)

 

회사에서 그룹사 통합 계정을 이용한다. 원래는 서비스 별로 나눠져 있던 인증이 하나로 합쳐진 것이다. 기존 api를 사용하여 새로 개발한 앱에서 비밀번호 오류가 있어도 로그인이 되는 문제가 발생. 그래서 기존 로그인 api를 확인했더니 비밀번호 확인이나 인증 서버 호출 없이 그냥 DB에서 아이디만 검색 후 데이터를 반환하고 있었다. 기존 앱에서는 잘 되는 인증이 왜 새로 개발한 앱에서만 안되나 했더니 기존 앱에서는 앱 자체에서 인증 서버로 인증을 요청하고 있었다.

그래서 새로 백엔드에서 인증 서버와 연동하여 로그인 하는 api가 필요하게 됐다. 찾아봤더니 RestTemplate와 WebClient를 많이 사용하는데 RestTemplate는 동기식이고 WebClient는 논블로킹 비동기 방식이다. WebClient를 쓰려면 Spring WebFlux를 사용해야 해서 일단 제외하고 RestTemplate를 사용하려 했는데 서버에서 이미 retrofit2로 구현된 외부 api 연동 util이 있어서 retrofit2로 추가 작성하기로 했다.

retrofit은 rest 통신 라이브러리다. OkHttp 라이브러리의 상위 구현체이고 동기/비동기 모두 사용이 가능하다.

 

Interface로 api 요청 메서드 작성

rest api 요청

// api util interface
@POST("v1/api/{apptype/login")
@Headers("accept: application/json", "content-type: application/json")
Call<LoginResponse> login(@Path("apptype") String apptype, @Body LoginRequest request);
  • 사용할 메서드와 요청할 url을 작성
  • @Path로 url의 파라미터 대입
  • @Header로 header 설정
  • @Body를 사용하면 객체를 json으로 전달할 수 있다.
  • Call: 요청을 보내고 응답을 반환, HTTP 요청과 응답 쌍을 생성(콜백 함수를 이용하여 응답에 대한 처리를 할 수 있다)
    • Call 대신 Response를 사용하면 응답의 결과에 대한 것만 수행(성공/실패)
  • <LoginResponse>: 요청에 성공했을 때 반환 받을 객체 타입

 

내가 필요한 건 x-www-form-urlencoded 방식이다. form을 submit할 때 요청하는 방식

// api util interface
@FormUrlEncoded
@POST("v1/api/login")
@Headers({"accept: application/json;charset=utf-8", "content-type: application/x-www-form-urlencoded"})
Call<LoginResponse> login(@Field("userid") String userid,
													@Field("password") String password);
  • @FormUrlEncoded: form submit 방식으로 요청할 때 사용하는 어노테이션
  • @Field: 객체로 전달이 불가능하고 보낼 파라미터를 하나하나 해당 어노테이션으로 명시하여야 한다.
  • @Query: 쿼리 파라미터
  • @Body: 객체를 json으로 전달
  • @path: path 파라미터

 

private static final Retrofit authApi = new Retrofit.Builder()
			.addConverterFactory(GsonConverterFactory.create())
			.baseUrl(AUTH_API_URL)
			.build();

private static final RetrofitApi authApi = authApi.create(TongTongUtilApi.class);

...

public static LoginResponse login(String userid, String password) {

	LoginResponse result;

	Call<LoginResponse> call = authApi.login(userid, password);

	Response<LoginResponse> response = call.execute();

	if(response.isSuccessful()) {
		return response.body();
	}

	return result;
}
  • 응답 코드가 200, 300일 경우 success로 처리
  • 에러 코드를 받았을 때 에러 응답 내용은 response.errorBody()로 받을 수 있다.
  • response.errorBody().string()을 하면 json 형태의 문자열을 얻을 수 있다.
  • errorBody()로 응답 객체를 생성하면 된다.

 

비동기

call.execute()는 동기 처리고 call.enqueue()는 비동기 처리다.

인자로 Callback을 보내 응답이 오면 콜백 함수를 실행한다.

Response<LoginResponse> response = call.enqueue(new Callback<LoginResponse> {
    @Override
    public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
        ...
    }
 
    @Override
    public void onFailure(Call<LoginResponse> call, Throwable t) {
        ...
    }
});