[SwiftUI] - Papago API (with. HTTP Protocol)

Ben·2023년 5월 23일
0

iOS

목록 보기
1/23
post-thumbnail

Overview

Papago API를 활용하여 HTTP 통신을 하고 다국어 번역기능을 구현한다.

SwiftUI FrameworkMVVM Design Patterm 기반으로 작성되었습니다.


Result

Picker의 Target Language를 설정하면 그 언어에 맞게 번역된다.


Implementation

먼저 알아야할 사항들이 있다.

N사의 Papago API는 RESTful API 라고 한다.

위의 RESTful API 문서를 잘 읽어보면,
결국 돌아가는 메커니즘은 Client가 Server와 통신하기 위해 Client가 Request를 하면 Server가 그에 맞는 Response를 해주는 시스템이고, 서로 'Message' 라는 매개체를 가지고 소통한다.

Client가 요청하는 메시지 안에 아래의 3가지가 들어간다.

  • 고유 리소스 식별자 (-> URL = Uniform Resource Locator)
  • 메서드 (-> GET, POST, PUT, DELETE)
  • HTTP 헤더 (-> Data, Parameters)

그중에서, HTTP 헤더

위와 같이 구성되어진다. (-> 자세한 내용은 MDN의 내용을 참조)
이 구조를 알아야 RESTful API의 원리를 알고 사용할 수 있다.

결국 Papago API를 사용하려면 HTTP 통신에 필요한 구조에 대해 알아야한다.

Reference

사용한 API에 대한 정보는 아래 링크에서 확인할 수 있다.


우선 Papago API가 알려준 내용을 토대로 HTTP 헤더를 형식에 맞추어 완성하면 된다.

let clientID = Bundle.main.CLIENT_ID    //  클라이언트 아이디
let clinetSecret = Bundle.main.CLIENT_SECRET    //  클라이언트 시크릿

var request = URLRequest(url: url)
        
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue(clientID, forHTTPHeaderField: "X-Naver-Client-Id")
request.setValue(clinetSecret, forHTTPHeaderField: "X-Naver-Client-Secret")

URLRequest타입인 request 변수의 .httpMethod 인스턴스 프로퍼티를 "POST"로 설정하여 Message의 Start-Line을 완성한다. (-> '.httpMethod'의 Default 값이 "GET" 이다.)

그리고 .setValue(_:forHTTPHeaderField:) 메서드를 사용하여

  • Content-Type
  • X-Naver-Client-Id
  • X-Naver-Client-Secret

Message의 Header Field값을 설정한다.

❗ Client-Id와 Client-Secret의 값은 노출되면 안되는 값이기에 현재는 .plist 파일로 따로 빼놓았다.

Message의 Body Field은

MDN에서 설명한 바와 같이

  • GET
  • HEAD
  • DELETE
  • OPTIONS

이 4가지의 경우가 아니면 생략해도 무방하지만, Papago API에서는 POST 방식을 채택하기에 넣어주어야 한다.

let stringWithParameters = "source=ko&target=\(target)&text=\(sourceString)"    //  Data Query,	원본언어: 한국어 (ko) -> 목적언어: target 파라미터 (즉, 영어(en), 중국어 간체(zh-CN), 일본어(ja))
let data = stringWithParameters.data(using: .utf8)!

request.httpBody = data

.httpBody 인스턴스 프로퍼티는 Data 타입이기에
API에서 알려준 Params 'source', 'target', 'text' 파라미터들을 이용한 Data Query인 stringWithParameters String타입의 상수를
Optional Data 타입을 반환하는 .data(using:) 메서드를 사용하여
Message의 Body Field를 채워주었다.

.data(using:) 메서드에서 using 인수에 .utf8로 설정한 이유는
Request에 성공하면 API에 Response로 주는 결과값이 JSON 데이터 이다.

즉, Request와 Response 과정에서 데이터를 쉽게 Encoding, Decoding 하기 위한 방식으로 UTF-8을 사용했다.

추가로 API의 Content-Type 헤더 필드의 charset이 UTF-8 이다.

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

이제 Request를 해야한다.

let (responseData, _) = try await URLSession.shared.upload(for: request, from: data)

데이터를 요청하고 응답받는 작업은 await 키워드를 이용해 비동기 (= Asynchronous) 처리해주었다.
URLSession을 통해 request하는 메서드는 .upload(for:from:delegate:) 를 사용하면 된다.

이렇게 요청을 했으면 JSON 데이터를 결과값으로 주는 응답값을 받아 decoding 해주어야 하므로,

let response: TranslateResponse = decodeData(responseData)
let translatedString = response.message.result.translatedText

func decodeData <T: Decodable> (_ data: Data) -> T {

	do {
		return try JSONDecoder().decode(T.self, from: data)
	} catch (let error) {
		print(error)
		preconditionFailure("Fail to decode Data")
	}
}

응답값을 decodeData(_ data: Data) 메서드를 사용해 response 변수를 dump() 메서드로 확인해보면

API의 응답 예시처럼 JSON 데이터로 나온다.

여기서 실제로 얻고 싶은 값은 result Key의 Value이기 때문에 JSON 형식에 맞추어

import Foundation

struct Message: Decodable {

    let type: String
    let service: String
    let version: String
    let result: Result

    enum CodingKeys: String, CodingKey {
        case result
        case type = "@type"
        case service = "@service"
        case version = "@version"
    }
}

struct Result: Decodable {
    let translatedText: String
}

struct TranslateResponse: Decodable {
    let message: Message
}

구조체를 생성해주고

let translatedString = response.message.result.translatedText
        
return translatedString

translatedString 값을 반환해주면 다국어 번역 기능이 완성된다.

profile
 iOS Developer

0개의 댓글