-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial(3) Profile Image Upload API 연동하기
오늘은 프로필 이미지를 업로드하는 서버 API와 연결해보는 작업을 진행하도록 하겠습니다.
_
(로그인한 상태로) 유저가 프로필 이미지로 등록할 사진을 선택 → 업로드할 링크 전송받으면 해당 URL과 헤더로 실제 파일을 전송한다.
import UIKit
// #1
class ImageUploadProcessor {
// #2
let image: UIImage?
var api: RestManager!
init(
image: UIImage?,
api: RestManager! = RestManager()
) {
self.image = image
self.api = api
self.api.requestDelegate = self
self.getUploadLink()
}
// #3
func upload() {
}
// #4
func getUploadLink() {
guard let url = URL(
string: APIEndPoint
.uploadLink
.description) else { return }
guard let accessToken = KeyChain.shared[
Constants
.accessToken
.description ] else { return }
api.requestHttpHeaders.add(value: "application/json", forKey: "Content-Type")
api.requestHttpHeaders.add(value: "Token \(accessToken)", forKey: "Authorization")
api.httpBodyParameters.add(value: "test.png", forKey: "filename")
api.httpBodyParameters.add(value: "image/png", forKey: "content_type")
api.httpBodyParameters.add(value: 20104, forKey: "byte_size")
api.httpBodyParameters.add(value: "oO5Ege6FrZw+1RhWzlGPuw==", forKey: "checksum")
api.makeRequest(toURL: url, withHttpMethod: .post)
}
}
// #5
extension ImageUploadProcessor: RestManagerRequestDelegate {
func didFailToPrepareRequest(_ result: RestManager.Results) {
print("API 실패")
}
func didReceiveResponseFromDataTask(_ result: RestManager.Results) {
print(result)
guard result.response?.httpStatusCode == 200 else { return }
print("API 성공")
guard let data = result.data,
let decoded = try? JSONDecoder().decode(
UploadLinkResult.self,
from: data
) else { return }
print(decoded)
}
}
// #6
struct UploadLinkResult: Codable {
let result: UploadLinkDTO
}
struct UploadLinkDTO: Codable {
let upload: UploadDTO
}
struct UploadDTO: Codable {
let id: String
let url: String
let headers: String
}가장 먼저 ImageUploadProcessor라는 class를 만들어줍니다.
class ImageUploadProcessor {
}class ImageUploadProcessor 안에는 서버 연동과 필요한 작업들이 선행되어야 합니다.
class ImageUploadProcessor {
let image: UIImage?
var api: RestManager!
init(
image: UIImage?,
api: RestManager! = RestManager()
) {
self.image = image
self.api = api
self.api.requestDelegate = self
self.getUploadLink()
}
}예전에 만들어 둔 RestManager를 활용해 리퀘스트를 요청할 예정입니다.
우리가 필요한 것은 업로드할 1)이미지와 2)api 입니다.
클래스, 구조체, 열거형 인스턴스를 사용하기 위해 이니셜라이저(initializer)로 준비를 해줍니다.
또한 image, api, requestDelegate를 사용하겠다라는 내용을 생성자에 명시해줍니다.
그리고 오늘 저희가 만들 func 함수 getUploadLink도 함께 명시해줍니다.
*// 아직 함수 코드 구현 중..*func getUploadLink() {
guard let url = URL(
string: APIEndPoint
.uploadLink
.description) else { return }
guard let accessToken = KeyChain.shared[
Constants
.accessToken
.description ] else { return }
api.requestHttpHeaders.add(value: "application/json", forKey: "Content-Type")
api.requestHttpHeaders.add(value: "Token \(accessToken)", forKey: "Authorization")
api.httpBodyParameters.add(value: "test.png", forKey: "filename")
api.httpBodyParameters.add(value: "image/png", forKey: "content_type")
api.httpBodyParameters.add(value: 20104, forKey: "byte_size")
api.httpBodyParameters.add(value: "oO5Ege6FrZw+1RhWzlGPuw==", forKey: "checksum")
api.makeRequest(toURL: url, withHttpMethod: .post)
}자, 이제 업로드 링크를 받는 함수를 만들어보겠습니다.
가장 첫 번째로 필요한 부분들은 어떤 API 링크로 보낼지 URL 설정과
유저의 넘겨주고 싶은 정보인 ID의 Access Token 을 상수에 담아줍니다.
guard let url = URL(string: APIEndPoint.uploadLink.description) else { return }
guard let accessToken = KeyChain.shared[Constants.accessToken.description ] else { return }_
그 다음 우리는 Request를 하기 위해 필요한 조건들을 생성해줍니다.
api.requestHttpHeaders.add(value: "application/json", forKey: "Content-Type")
api.requestHttpHeaders.add(value: "Token \(accessToken)", forKey: "Authorization")
api.httpBodyParameters.add(value: "test.png", forKey: "filename")
api.httpBodyParameters.add(value: "image/png", forKey: "content_type")
api.httpBodyParameters.add(value: 20104, forKey: "byte_size")
api.httpBodyParameters.add(value: "oO5Ege6FrZw+1RhWzlGPuw==", forKey: "checksum")
api.makeRequest(toURL: url, withHttpMethod: .post)-
Key: Content-Type, Value: application/json → json 형식의 Content-Type
-
Key: Autorization, Value: Token (accessToken) → 유저의 accessToken (ID)
-
Key: filename → 파일
-
Key: content_type
-
Key: byte_size
-
Key: checksum
→ 위의 정보들을 코드로 작성해주었다면 우리는 Request를 생성하여 Post합니다.
extension ImageUploadProcessor: RestManagerRequestDelegate {
func didFailToPrepareRequest(_ result: RestManager.Results) {
print("API 실패")
}
func didReceiveResponseFromDataTask(_ result: RestManager.Results) {
print(result)
guard result.response?.httpStatusCode == 200 else { return }
print("API 성공")
guard let data = result.data,
let decoded = try? JSONDecoder().decode(
UploadLinkResult.self,
from: data
) else { return }
print(decoded)
}
}1. func didFailToPrepareRequest (실패 여부를 알려주는 func)
func didFailToPrepareRequest(_ result: RestManager.Results) {
print("API 실패")
}2. func didReceiveResponseFromDataTask (성공했다면 어떤 기능을 수행하라는 func)
func didReceiveResponseFromDataTask(_ result: RestManager.Results) {
print(result) // result의 값을 보고싶어서 작성한 코드
guard result.response?.httpStatusCode == 200 else { return }
print("API 성공")
guard let data = result.data,
let decoded = try? JSONDecoder().decode(
UploadLinkResult.self,
from: data
) else { return }
print(decoded)
}2-1) httpStatusCode가 200이라면 API 성공!
guard result.response?.httpStatusCode == 200 else { return }
print("API 성공")2-2) 성공일 경우, JSON 형태의 Data를 파싱해주는 역할 수행!
guard let data = result.data,
let decoded = try? JSONDecoder().decode(
UploadLinkResult.self,
from: data
) else { return }
print(decoded)decode는 Decodable을 준수해야 하는데 필요한 조건들이 있습니다.
바로 T.Type과 Data를 넘겨줘야 하죠.
open func decode<T>(
_ type: T.Type,
from data: Data
) throws -> T where T : Decodable그렇기 때문에 우리가 파싱하고자 하는 struct의 type과 data를 써준 것입니다.
// #6
struct UploadLinkResult: Codable {
let result: UploadLinkDTO
}
struct UploadLinkDTO: Codable {
let upload: UploadDTO
}
struct UploadDTO: Codable {
let id: String
let url: String
let headers: String
}JSON Data의 Key 값은 Codable을 따르는 구조체의 속한 상수명과 매칭이 되어야 합니다.
따라서, result 결과 값안에 UploadLinkDTO, UploadDTO가 출력되는 형태로 코드를 구현했습니다.