멀고도 험난한 개발 일지

이런저런_구글링_2 - Alamofire, 얼탱이 없는 Moya..

이드entity 2022. 6. 23. 18:38
반응형

Alamofire를 이용한 JSON 형식의 서버 통신

지난번엔 URLSession을 사용해서 POST와 하는 법을 올렸었다
이런저런_구글링_1 - Date to String, Design Pattern, Voice Recorder, Post Method

 

먼저, Alamofire, Moya 등 여러 서버 통신용 프레임워크가 있는데 왜 URLSession을 쓰나!
URLSession을 사용하면 통신 과정 중 더 많은 커스텀(?)이 가능하기 떄문..!!
하지만 현재 앱에서는 그런게 필요 없기 때문에 이미 주어진 프레임워크를 사용하는게 더 편리하다

 

일단 코드를 보자..!

import Foundation
import Alamofire

let parameters: [String: [String]] = [
    "foo": ["bar"],
    "baz": ["a", "b"],
    "qux": ["x", "y", "z"]
]

func testGetRequest(url: URL) {
    AF.request(url).response { response in
        debugPrint(response)
    }
}

func testPostRequest(url: URL) {
    AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in
        debugPrint(response)
    }
}

testGetRequest(url: URL(string: "http://13.124.90.96:8080/api/v1/testing/test")!)
testPostRequest(url: URL(string: "http://13.124.90.96:8080/api/v1/testing/test")!)

일단은 간단하게 POST와 GET만 구현!

Alamofire에서 default로 제공하는 HTTP Method는 Get이기 때문에

AF.request(url).response

이렇게만 넣어도 get 통신은 잘 됨!



만약 다른 Method(예시로 Post)를 사용한다면

AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).response

method에 .post를 추가하면 된다!

parameter에는 전달할 인자를 입력하고,

encoding에는 encoding 방식 입력 → 현재는 JSONEncoding 방식 사용

이런 추가적인 요소를 지정할 필요가 있다!

사실 URL 넣을 때에도 force unwrapping하면 안되지만.. 일단은 넘어가자 ㅎ

참고자료
Alamofire/Usage.md at master · Alamofire/Alamofire

 

 


 

Alamofire를 이용한 multipartFormat 형식의 POST

많은 경우에 텍스트만 주고받고, 이런 경우에는 그냥 JSON 형식으로 소통하면 된다


하지만 이번 프로젝트에서는 이미지나 음성메세지 등의 파일들도 주고받아야 했기 때문에
이건 어떻게 해야하나 엄청 구글링 했다...

 

먼저 multipart/form-data라 함은,

 

모든 문자를 인코딩하지 않음을 명시
이 방식은 form 요소가 파일이나 이미지를 서버로 전송할 때 주로 사용

 

하는 것이라고 한다🤔

 

사실 저게 무슨 의미인지 아직은 잘 모르겠고,
일단은 텍스트 외의 다른 데이터들을 넘길 때 사용하는 것이라 이해했다..!

 

이거를 Alamofire에서 사용했는지 아래 코드를 보자!

let urlpath = Bundle.main.path(forResource: "IMG_5688", ofType: "JPG")
let url = URL(fileURLWithPath: urlpath!)

func testMultipartUpload(to: URL, url: URL) {

    let fileName = url.lastPathComponent
    guard let imageFile: Data = try? Data (contentsOf: url) else {return}

    AF.upload(multipartFormData: { (multipartFormData) in
        multipartFormData.append(imageFile, withName: "image", fileName: fileName, mimeType: "image/jpg")
    }, to: to).responseJSON { (response) in
        debugPrint(response)
    }

}

testMultipartUpload(
    to: URL(string: "http://13.124.90.96:8080/api/v1/testing/image")!,
    url: url
)

로컬에 있는 이미지를 업로드 하는 과정이다..!


먼저 로컬의 파일이 어디에 있는지 URL 형태로 받아와야 한다

let urlpath = Bundle.main.path(forResource: "IMG_5688", ofType: "JPG")
let url = URL(fileURLWithPath: urlpath!)



업로드하는 함수 만들기!

func testMultipartUpload(to: URL, url: URL) {

    let fileName = url.lastPathComponent
    guard let imageFile: Data = try? Data (contentsOf: url) else {return}

    AF.upload(multipartFormData: { (multipartFormData) in
        multipartFormData.append(imageFile, withName: "image", fileName: fileName, mimeType: "image/jpg")
    }, to: to).responseJSON { (response) in
        debugPrint(response)
    }

}



Alamofire의 multipartFormData()를 사용하여 저장될 파일의 이름명 정하기

let fileName = url.lastPathComponent



처음에 가져온 url로 Data 형태 만들기

guard let imageFile: Data = try? Data (contentsOf: url) else {return}



갓갓 Alamofire에서 multipartFormData를 업로드하기 위해 upload() 사용!

AF.upload(
        multipartFormData: { (multipartFormData) in
            multipartFormData.append(
                        imageFile, 
                        withName: "image", 
                        fileName: fileName, 
                        mimeType: "image/jpg")}, 
        to: to)
        .responseJSON { (response) in
            debugPrint(response)
}

여기서 append 내부의 여러가지 입력 요소들을 보자면,

 

multipartFormData는 전달할 데이터 파일을 의미하고,

 

withName은 업로드할 서버에서 지정한 Request Body 이름,

 

fileName은 말 그대로 전달할 파일 명이고,

 

mimeType은 어떤 데이터인지, jpg, m4a 등등을 명시해주는 값이다!


사실 이 구문에서 responseJSON은 Alamofire6 부터 deprecated 될 것이라 하기 때문에 사용하면 안된다..

대신 responseData를 사용하자😉

.responseData { response in
    switch response.result {

    case .success(let data):
        let asJSON = try? JSONSerialization.jsonObject(with: data)
        print(asJSON!)

    case .failure(let error):
        print(error)
    }
}

do { … } catch { … } 문으로 JSONSerialization 할 때 제대로 안되면 오류 뜨도록 해야하는데, try 문 때문인지 do - catch 문 쓰면 어차피 catch로 갈 일 없다고 warning을 날리더라🤔



이전에 정해둔 업로드 할 서버 url 과 파일 url 을 입력으로 넣기!

testMultipartUpload(
    to: URL(string: "http://13.124.90.96:8080/api/v1/testing/image")!,
    url: url
)

이미지 뿐만 아니라 녹음파일도 가능한듯!!



참고자료
Alamofire/Usage.md at master · Alamofire/Alamofire

Sending recorded audio file to server by using Alamofire 5 beta newest Version

 


 

얼탱이 없는 Moya..인 줄 알았지만 미안 Moya🫠

코드를 작성하면서 GET Request를 날렸는데...

 

무조건 될 코드라고 생각했는데...

 

계속 무슨 일인지 모르게 %E2%80%8B 이런 문자들이 path에 덧붙여졌다…🤬

 

원래는 "api/v1/gifts/voicemail"을 넣으려고 했는데,

 

“api%E2%80%8B/v1%E2%80%8B/gifts%E2%80%8B/voicemail%E2%80%8B” 이렇게 이상한 값들이 덧붙는거다..!

 

구글링을 해봐도 왜 이런지 안나오고, 어떻게 해결해야 하나 싶었는데,

 

갓갓 멘토님 Judy가 왜 그런지 알려주셨다!

 

이유는.. path를 웹에서 복사한걸 코드에 붙여넣기 했기 때문...........

웹에 올라가있는 문자들은 인코딩 되어 있는 경우가 많다고 하더라🤔

그래서 저런 문자열이 붙는거다 이말이지..

 

암튼 쟤 때문에 우리 팀원 Milli도 고생을 많이 했었는데

결국 잘 해결돼서 다행이라 생각😮‍💨

반응형