도서리뷰 앱 만들기 (1) - Open Api 통해 도서목록 가져오기

2022. 12. 21. 22:25Android

-인터파크 Api 를통해 도서목록을 가져오기.

네이버나 구글에 검색해서 사이트를 들어가 캡쳐햇습니다,,

 

1. 요청 URL (request url)

http://book.interpark.com/api/bestSeller.api

2-1. 요청 변수 (request parameter)

요청 변수값설명

key string (필수) 이용 등록을 통해 받은 인증키를 입력합니다.
categoryId 분야의 고유 번호(필수)
카테고리 파일 다운.
지정한 카테고리의 베스트 셀러를 검색합니다.

2-2. 상세 검색-요청 변수 (request parameter)

※ 상세 검색은 검색 필수 사항을 보자 세부적으로 설정하여 검색할 수 있도록 합니다.

요청 변수변수 옵션설명

output xml(기본값) : REST XML형식
json : JSON방식
검색 결과의 출력 방식을 설정합니다.

 --> Chrome  Postman 으로 작성.

간단하게 API 가 동작하는 지 우선확인해보고 싶어서 결과를 확인해보았습니다.

 

GRADLE  의존성 추가

-모듈에 의존성을 추가해준다.

mplementation 'com.squareup.retrofit2:retrofit:버전'
implementation 'com.google.code.gson:gson:버전'
implementation 'com.squareup.retrofit2:converter-gson:버전'

- 괄호안에  버전을  넣으라고하는데 깃허브들어가면  버전이 잇어 최근에맞게 넣어주면된다.

  • gson 라이브러리에서 파싱한 것을 dto 객체로 바꿔주는 라이브러리
  • Retrofit의 필수 라이브러리 (최신버전은 retrofit와 같은걸써야한다.)
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:converter-gson:2.7.1

-gson

 

gson은 이 json을 편하게 사용할 수 있도록 google에서 만든 json관련 라이브러리 입니다.

json과 java객체 간의 직렬화(Serialization)와 역직렬화(Deserialization)를 쉽게 할 수 있게 도와주기 때문에 json자체의 파싱보다는 업무로직 자체에 집중할 수 있도록 도와줍니다.

dependencies {
  implementation 'com.google.code.gson:gson:2.10'
}
  • API 패키지 파일을 생성해준다.
  • BookService 인터페이스를 만들어줍니다.

 

package com.example.myapplication.api


import com.example.myapplication.model.BestSellerDTO
import com.example.myapplication.model.SearchBookDTO
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

interface BookService {

    @GET("/api/search.api?output=json")
    fun getBooksByName(
        @Query("key") apiKey: String,
        @Query("query") keyword: String,
    ): Call<SearchBookDTO>

    @GET("/api/bestSeller.api?output=json&categoryId=100")
    fun getBestSellerBooks(
        @Query("key") apiKey: String

        ): Call<BestSellerDTO>
}

 GET : 데이터 요청 시 반환 http

 POST : http body에 넣어 전달

 -> 모델이 없기때문에  Book이라는 데이터클래스를 만들어줍니다

package com.example.myapplication.model

import com.google.gson.annotations.SerializedName

data class Book (
   @SerializedName("itemId") val id:Long,
   @SerializedName("title") val title :String,
   @SerializedName("description") val description: String,
   @SerializedName("coverSmallUrl") val coverSmallUrl: String
        )

 전체모델에서 데이터를 꺼내올수있게 DTO도 만들어줍니다.

  • SearchBookDTO
package com.example.myapplication.model

import com.google.gson.annotations.SerializedName

data class SearchBookDTO (
    @SerializedName("title") val title: String,
    @SerializedName("item") val books: List<Book>
        )
  • BestrSellerDTO
package com.example.myapplication.model

import com.google.gson.annotations.SerializedName

data class BestSellerDTO (
    @SerializedName("title") val title: String,
    @SerializedName("item") val books: List<Book>
)
  • API 호출하기
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

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

 위에 코드를 참고로  인터페이스를 구현해서 메인클래스를 생성

 

  •  이 책을 표시하는 리사이클러뷰 목록화면구성 
  • 뷰바인딩 그래드모듈에 추가한다.
  • 어댑터에서 해당 레이아웃 해당하는 바인딩을 사용해 코드작성
package com.example.myapplication.Adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.databinding.ItemBookBinding
import com.example.myapplication.model.Book

// 어댑터 준비
class BookAdapter : ListAdapter<Book, BookAdapter.BookitemViewHolder>(diffUtil) {
// 뷰 홀더 준비
    inner class BookitemViewHolder(private val binding: ItemBookBinding) : RecyclerView
    .ViewHolder(binding.root) {
        fun bind(bookModel: Book) {
            binding.titleTextView.text = bookModel.title

        }
    }

    // 미리 만들어진 뷰 홀더가 없을 경우 생성하는 함수.
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookitemViewHolder {
        return BookitemViewHolder(ItemBookBinding.inflate(LayoutInflater.from(parent.context),
            parent,
            false))
    }

    //실제 뷰 홀더가 뷰에 그려지게 됬을 때 데이터를 바인드하게 되는 함수
    override fun onBindViewHolder(holder: BookitemViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

     //같은 값이 있으면 할당 해줄 필요없다.
    companion object {
        val diffUtil = object : DiffUtil.ItemCallback<Book>() {
            override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean {
                return oldItem == newItem
            }

            override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean {
                return oldItem.id == newItem.id
            }

        }
    }
}
  • 메인액티비티 코드 작성
package com.example.myapplication


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication.Adapter.BookAdapter
import com.example.myapplication.api.BookService
import com.example.myapplication.databinding.ActivityMainBinding
import com.example.myapplication.model.BestSellerDTO
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var adapter: BookAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initBookRecyclerView()


        val retrofit = Retrofit.Builder()
            .baseUrl("https://book.interpark.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        var bookService = retrofit.create(BookService::class.java)

        //베스트 셀러가져오기
        bookService.getBestSellerBooks("54538E2B4AC7B8E584CA2D046AF776BCE8C2E736B3F0019D1C50B09EAB47A963")
            .enqueue(object : Callback<BestSellerDTO> {
                override fun onResponse(
                    call: Call<BestSellerDTO>,
                    response: Response<BestSellerDTO>,
                ) {
                    if (response.isSuccessful.not()) {
                        Log.e(TAG, "NOT!! SUCCESS")
                        return
                    }
                    //받은 응답의 바디가 채워져잇을때(null이 아닐때) 블록이 실행됨
                    response.body()?.let {
                        Log.d(TAG, it.toString())

                        it.books.forEach { book ->
                            Log.d(TAG, book.toString())
                        }
                        adapter.submitList(it.books)
                    }
                }

                override fun onFailure(call: Call<BestSellerDTO>, t: Throwable) {
                    Log.e(TAG, t.toString())
                }

            })
    }

    private fun initBookRecyclerView() {
        adapter = BookAdapter()

        binding.bookRecyclerView.layoutManager = LinearLayoutManager(this)
        binding.bookRecyclerView.adapter = adapter
    }

    companion object {
        private const val TAG = "MainActivity"
    }
}

 

 실행했더니 에러가낫다.. 최신버전이라서 그런지  아래있는  그래들에 종속성을 추가해주자.

implementation 'com.squareup.okhttp3:okhttp:4.9.2'

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

이렇게 세개의 종속성이 추가된걸볼수있다, 

 

-애뮬레이터 실행화면 

아직 이미지뷰를 만들지않앗기때문에 다음에는 이미지뷰를 넣어 도서목록리스트랑 검색페이지를 만들어보겟다