๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป Programming/iOS

[iOS] Request Methods๋ฅผ ๊ณ๋“ค์ธ Alamofire ๊ฐ„๋‹จ ์‚ฌ์šฉ๋ฒ•

by ๊ธฐ๋ฌด์ • 2025. 2. 27.

์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด, ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š” ๋ถ€๋ถ„์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ, ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” Foundation์˜ URLSession์„ ์‚ฌ์šฉํ•˜์—ฌ ๋„คํŠธ์›Œํ‚น์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ, URLSession์€ ๋‹ค์†Œ ๋ฒˆ๊ฑฐ๋กœ์šด ์ ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜คํ”ˆ ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ Alamofire๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

Alamofire

Alamofire๋Š” swift๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ HTTP ๋„คํŠธ์›Œํ‚น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์•ž์—์„œ ์–ธ๊ธ‰ํ•œ Foundation์˜ URLSession ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด, ์ด๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 

https://github.com/Alamofire/Alamofire

 

GitHub - Alamofire/Alamofire: Elegant HTTP Networking in Swift

Elegant HTTP Networking in Swift. Contribute to Alamofire/Alamofire development by creating an account on GitHub.

github.com

 

 

Alamofire๋Š” ๋‹ค์Œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Chainable request/response methods
  • JSON, Codable decoding
  • Authentication

์š”์•ฝํ•˜์ž๋ฉด, Alamofire๋Š” HTTP ๋„คํŠธ์›Œํ‚น์„ ํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ๋ฐ ํ•จ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.


๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ”๋กœ Request Methods ์ž…๋‹ˆ๋‹ค.

 

 

Request Methods

Request Methods๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ์‚ฌ์šฉ์ž ์š”์ฒญ์˜ ๋ชฉ์ ์ด๋‚˜ ์ข…๋ฅ˜๋ฅผ ์•Œ๋ฆฌ๋Š” ์ˆ˜๋‹จ์ž…๋‹ˆ๋‹ค.
์ด ์ค‘์—์„œ๋„ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ ์œ„์ฃผ๋กœ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

HEAD

GET๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์‘๋‹ต ๋ณธ๋ฌธ์„ ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฆฌ์†Œ์Šค์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜, Content-Length ๋ฐ Last-Modified์™€ ๊ฐ™์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ณธ๋ฌธ์„ ์ „์†กํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

HEAD /api/resource HTTP/1.1
Host: example.com

 

 

GET

์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ€์ง€๋ฏ€๋กœ ๋™์ผํ•œ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋”๋ผ๋„ ์„œ๋ฒ„์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์บ์‹ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๋‚˜ ํ”„๋ก์‹œ ์„œ๋ฒ„๊ฐ€ ์‘๋‹ต์„ ์ €์žฅํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์‹œ์—๋Š” URL์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

GET /api/users?id=123 HTTP/1.1
Host: example.com

 

 

POST

์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฏ€๋กœ ๋™์ผํ•œ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋ฉด ์„œ๋ฒ„์˜ ์ƒํƒœ๊ฐ€ ๋‹ฌ๋ผ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ๋“ฑ๋ก, ๋กœ๊ทธ์ธ, ๋ฐ์ดํ„ฐ ์ œ์ถœ ๋“ฑ์˜ ์ž‘์—…์—์„œ ์ฃผ๋กœ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.

POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "name": "John Doe",
    "email": "john@example.com"
}

 

 

PUT

์ง€์ •๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์ „์ฒด์ ์œผ๋กœ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. GET๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ๋ฆฌ์†Œ์Šค๊ฐ€ ์กด์žฌํ•˜๋ฉด ๋ฎ์–ด์“ฐ๊ธฐ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์—๋Š” ๋ฆฌ์†Œ์Šค์˜ ์ „์ฒด ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ๋ถ€๋ถ„์ ์ธ ์—…๋ฐ์ดํŠธ๋ณด๋‹ค๋Š” ์ „์ฒด ๊ฐฑ์‹ ์ด ํ•„์š”ํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "name": "Jane Doe",
    "email": "jane@example.com"
}

 

 

DELETE

์„œ๋ฒ„์—์„œ ํŠน์ • ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ€์ง€๋ฏ€๋กœ ๋™์ผํ•œ ์š”์ฒญ์„ ๋ฐ˜๋ณตํ•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„์˜ ์ •์ฑ…์— ๋”ฐ๋ผ ์š”์ฒญ ์ฆ‰์‹œ ์‚ญ์ œ๋˜๊ฑฐ๋‚˜ ์ผ์ • ๊ธฐ๊ฐ„ ๋ณด๊ด€ ํ›„ ์‚ญ์ œ๋  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ, ์ผ๋ถ€ ๊ตฌํ˜„์—์„œ๋Š” ์‚ญ์ œ ์š”์ฒญ์„ ๋ฐ›์€ ํ›„ ๋น„ํ™œ์„ฑํ™” ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹๋„ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

DELETE /api/users/123 HTTP/1.1
Host: example.com

 

 

Request/Reponse

์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ API ์š”์ฒญ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

GET

let url = "https://test.com"

AF.request(
        url,
        method: .get,
        parameters: nil,
        encoding: URLEncoding.default,
        headers: ["Content-Type":"application/json", "Accept":"application/json"]
    ).validate(statusCode: 200..<300)
    .responseJSON { response in
     
    /** ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฐ์ดํ„ฐ ํ™œ์šฉ */
    switch response.result {
        case .success(let data):
            /** ์ •์ƒ์ ์œผ๋กœ reponse๋ฅผ ๋ฐ›์€ ๊ฒฝ์šฐ */
        case .failure(let error):
            /** ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ */
    }
}
  • url : ์š”์ฒญํ•  url
  • method : ์–ด๋–ค request method๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€ ์ž‘์„ฑ
  • parameters : request body๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ „๋‹ฌํ•  ๊ฐ’ (GET์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ nil)
  • encoding : ์ธ์ฝ”๋”ฉ ๋ฐฉ์‹
  • headers : ๋ถ€๊ฐ€์ ์ธ ์ •๋ณด๋ฅผ ์˜๋ฏธ (์ฝ”๋“œ์—์„œ๋Š” ์†ก/์ˆ˜์‹  ๋ฐ์ดํ„ฐ ํƒ€์ž…(JSON)์„ ๋‚˜ํƒ€๋ƒ„)
  • validate : ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌ (state code ๊ฐ’์ด 20x ์ผ ๋•Œ๊ฐ€ ์†ก/์ˆ˜์‹ ์ด ์›ํ™œํ•˜๊ฒŒ ๋œ ๊ฒฝ์šฐ)
  • responseJSON : ์‘๋‹ต json ๋ฐ์ดํ„ฐ

 

POST

POST ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” parameters์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

let url = "https://test.com"
let params = ["id":"testId", "pw":"testPassword"] as Dictionary

AF.request(
        url,
        method: .post,
        parameters: params,
        encoding: JSONEncoding(options: []),
        headers: ["Content-Type":"application/json", "Accept":"application/json"]
    ).responseJSON { response in

    /** ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฐ์ดํ„ฐ ํ™œ์šฉ */
    switch response.result {
        case .success(let data):
            /** ์ •์ƒ์ ์œผ๋กœ reponse๋ฅผ ๋ฐ›์€ ๊ฒฝ์šฐ */
        case .failure(let error):
            /** ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ */
    }
}

 

 

File Upload

Alamofire๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ฑฐ๋‚˜, ์—…๋กœ๋“œํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐ์— ๋งž๊ฒŒ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋Š” for๋ฌธ์„ ์‚ฌ์šฉํ•ด ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

for (key, value) in parameters {
    multipartFormData.append("\(value)".data(using: .utf8)!, withName: key)
}

 

 

์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

if let image = imageData?.pngData() {
    multipartFormData.append(image, withName: "activityImage", fileName: "\(image).png", mimeType: "image/png")
}

 

  • value : ์ „๋‹ฌํ•  ํŒŒ์ผ
  • withName : key
  • fileName : ์„œ๋ฒ„์— ์—…๋กœ๋“œํ•  ํŒŒ์ผ ์ด๋ฆ„
  • mimeType : ํŒŒ์ผ ํ˜•์‹

 

let url = "https://test.com"

AF.upload(
        multipartFormData: { multipartData in /** ์„œ๋ฒ„๋กœ ์ „์†กํ•  ๋ฐ์ดํ„ฐ */ },
        to: url,
        method: .post,
        headers: ["Content-Type" : "multipart/form-data"]
    ).response { response in
    
    if response.error != nil {
        /** ํŒŒ์ผ ์—…๋กœ๋“œ ์‹คํŒจ */
    } else{
        /** ํŒŒ์ผ ์—…๋กœ๋“œ ์„ฑ๊ณต */
    }
}

 

์ด๋•Œ, GET์ด๋‚˜ POST ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” header์˜ Content-Type๊ฐ€ application/json์ด์—ˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ๋‹ค์šด๋กœ๋“œํ•  ๋•Œ๋Š” Content-Type์„ multipart/form-data๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

File Download

let url = "https://test.com/test.jpg"

/** ํŒŒ์ผ์— ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ */
let fileManager = FileManager.default
let appURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileName : String = URL(string: url)!.lastPathComponent /** url์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์—ด๋กœ ์ด๋ฆ„ ์ง€์ • */
let fileURL = appURL.appendingPathComponent(fileName)

/** ํŒŒ์ผ ๊ฒฝ๋กœ ์ง€์ • ๋ฐ ๋‹ค์šด๋กœ๋“œ ์˜ต์…˜ ์„ค์ • (์ด์ „ ํŒŒ์ผ ์‚ญ์ œ, ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ) */
let destination: DownloadRequest.Destination = { _, _ in
    return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}

AF.download(
        url,
        method: .get,
        parameters: nil,
        encoding: JSONEncoding.default,
        to: destination
    ).downloadProgress { progress in
        /** ๋‹ค์šด๋กœ๋“œ progress */
        /** progressView๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์—ฌ๊ธฐ์— ์ž‘์„ฑ */
    }.response { response in

        if response.error != nil {
            /** ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ*/
        } else{
            /** ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์„ฑ๊ณต*/
        }
    }

'๐Ÿ’ป Programming > iOS' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[iOS] WKWebView๋กœ ์›น๋ทฐ(WebView) ๊ตฌํ˜„ํ•˜๊ธฐ  (1) 2025.02.24