본문 바로가기
iOS Swift/Study

[Swift] 책검색 App (1) - 네트워크 통신

by 야고이 2024. 5. 5.
728x90

kakao Developers 책검색 api 를 활용해서 책 검색앱 만들기!

네트워킹부터 해볼게요,,

api key 를 받고 활용법 확인하기

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

가입한 후 api key 를 받아줍니다

 

인증방식이 REST API키 라고 하네요 !

헤더에 Authorization 를 넣는건 필수고

쿼리파라미터 중에 query .즉 검색값도 필수로 넣어줘야한다고 합니다 당연하죠 검색 api니까 검색 값이 있어야겠죠

 

 

데이터 확인하기 

데이터를 확인할 수 있는 프로그램들이 있는데 저는 insomnia 를 사용했습니다

헤더에 발급 받은 키를 넣습니다

 

파라밑 값에 필수 값인 query 값을 넣고 검색어는 임의로 '강화길' 이라는 값을 넣었어요

target 도 person 으로 넣어 줬습니다

데이터는 잘 나오네요 ! 

 

데이터모델 생성

https://app.quicktype.io/

 

Instantly parse JSON in any language | quicktype

 

app.quicktype.io

모델 생성해주는 사이트도 여러가지 이지만 전 위의 링크에서 만들었구요

주의 할 점은 생성한 후 제대로 맞게 생성 되었는지 실제 데이터랑 비교하면서 확인해야합니다

저도 배열값으로 들어오는건데 배열로 생성하지 않아서 네트워킹을 시도할 때 오류가 났어요

// MARK: - SearchBookResponse
struct SearchBookResponse: Codable {
    let documents: [Document]
    let meta: Meta
}

// MARK: - Document
struct Document: Codable {
    let authors: [String]
    let contents, datetime, isbn: String
    let price: Int
    let publisher: String
    let salePrice: Int
    let status: String
    let thumbnail: String
    let title: String
    let translators: [String]
    let url: String

    enum CodingKeys: String, CodingKey {
        case authors, contents, datetime, isbn, price, publisher
        case salePrice = "sale_price"
        case status, thumbnail, title, translators, url
    }
}

// MARK: - Meta
struct Meta: Codable {
    let isEnd: Bool
    let pageableCount, totalCount: Int

    enum CodingKeys: String, CodingKey {
        case isEnd = "is_end"
        case pageableCount = "pageable_count"
        case totalCount = "total_count"
    }
}

 

 

네트워크 통신

class BookManager {
    static let shared = BookManager()
    private init() {}

클래스를 만들고 싱글톤패턴으로 생성합니다

외부에서의 생성을 막고 전역에서 BokManager 에 접근 할 수 있습니다

 

let url = "https://dapi.kakao.com/v3/search/book"
let apiKey = " <발급받은 api 키> "

기본 url 과 발급 받은 키를 선언합니다

 

 func fetchBookData(withQuery query: String, targets: [SearchBookTarget] = [], completion: @escaping (Bool, SearchBookResponse?) -> Void) {

통신을 위해 메서드를 만들어서 사용할거예요

파라미터에는 아래 세가지를 넣을거예요

query: 검색값을 넣습니다

targets: 검색 대상을 나타내는 SearchBookTarget 열거형 case들의 배열입니다. 기본값은 빈 배열입니다.

target은 필수 값이 아니기 떄문에 값을 넣지않으면 전체 책목록에서 검색이 되고 target를 넣으면 그 안에서 검색이 됩니다

아래와 같이 enum으로 만들었어요

enum SearchBookTarget: String {
    case title, isbn, publisher, person
}

 

completion: 성공 또는 실패 여부를 나타내는 Bool 값과 선택적인 SearchBookResponse 객체를 매개변수로 받는 클로저입니다. 이 클로저는 책 데이터 검색이 완료되면 비동기적으로 호출됩니다.

 

URL 구성 설정

 guard var urlComponents = URLComponents(string: url) else {
            print("Invalid URL")
            return
}
var queryItems: [URLQueryItem] = [
    URLQueryItem(name: "query", value: query),
]

// target 값 있을시
if !targets.isEmpty {
    let target = targets.compactMap { x in x.rawValue }.joined(separator: ",")
    queryItems.append(URLQueryItem(name: "target", value: target))
}

urlComponents.queryItems = queryItems

guard let url = urlComponents.url else {
    print("Invalid URL")
    return
}

 

네트워크 요청

var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("KakaoAK \(apiKey)", forHTTPHeaderField: "Authorization")

 

URLSession 으로 Task 부여 및 실행

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

//오류처리
    if let error = error {
        print("Error \(error)")
        DispatchQueue.main.async {
            completion(false, nil)
        }
        return
    }
    guard let data = data else {
        DispatchQueue.main.async {
            completion(false, nil)
        }
        return
    }

//응답 JSON을 SearchBookResponse 객체로 디코딩
    do {
        let response = try JSONDecoder().decode(SearchBookResponse.self, from: data)
        DispatchQueue.main.async {
            completion(true, response)
        }
    } catch {
        //                        completion(.failure(error))
        print("json decode error \(error)")
        DispatchQueue.main.async {
            completion(false, nil)
        }

에러 처리를 하고 디코딩 합니다

 

task.resume()

요거 까먹지 말고 해줘야하구여!

후우 일단 여기까지

 

728x90

댓글