From 012ff20c96985c7cfdaba35d7979dd4dec882fd0 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Tue, 20 Oct 2020 21:09:53 -0700 Subject: [PATCH] Get rid of some pointless mutable state --- Readme.md | 12 ++++++---- Sources/Osiris/MultipartFormEncoder.swift | 8 +------ Sources/Osiris/RequestBuilder.swift | 5 +--- .../MultipartFormEncoderTests.swift | 24 +++++++++++-------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Readme.md b/Readme.md index 7d8d294..da08d3e 100644 --- a/Readme.md +++ b/Readme.md @@ -12,17 +12,19 @@ Copy the files you want to use into your project, and then customize them to sui Create an encoder and then add parts to it as needed: ```Swift -let encoder = MultipartFormEncoder() -encoder.addPart(.text(name: "email", text: "somebody@example.com")) -encoder.addPart(.text(name: "password", text: "secret")) let avatarData = UIImage(from: somewhere).jpegData(compressionQuality: 1) -encoder.addPart(.binary(name: "avatar", type: "image/jpeg", data: avatarData, filename: "avatar.jpg")) +let encoder = MultipartFormEncoder() +let body = encoder.encode(parts: [ + .text(name: "email", text: "somebody@example.com"), + .text(name: "password", text: "secret"), + .binary(name: "avatar", type: "image/jpeg", data: avatarData, filename: "avatar.jpg"), +]) ``` The entire form is encoded as `Data` in memory so you may not want to use this for more than a few megabytes at a time: ```Swift -let body = encoder.encode() +let body = encoder.encode(parts: [/* ... */]) var request = URLRequest(url: URL(string: "https://example.com/accounts")!) request.httpMethod = "POST" request.httpBody = body.data diff --git a/Sources/Osiris/MultipartFormEncoder.swift b/Sources/Osiris/MultipartFormEncoder.swift index f39505d..78bbd30 100644 --- a/Sources/Osiris/MultipartFormEncoder.swift +++ b/Sources/Osiris/MultipartFormEncoder.swift @@ -55,17 +55,11 @@ extension MultipartFormEncoder { final class MultipartFormEncoder { let boundary: String - private var parts: [Part] = [] - init(boundary: String? = nil) { self.boundary = boundary ?? "LifeIsMadeOfSeconds-\(UUID().uuidString)" } - func addPart(_ part: Part) { - parts.append(part) - } - - func encode() -> Body { + func encode(parts: [Part]) -> Body { var bodyData = Data() for part in parts { // Header diff --git a/Sources/Osiris/RequestBuilder.swift b/Sources/Osiris/RequestBuilder.swift index 13a08ad..81c508e 100644 --- a/Sources/Osiris/RequestBuilder.swift +++ b/Sources/Osiris/RequestBuilder.swift @@ -37,10 +37,7 @@ final class RequestBuilder { case .multipart: let encoder = MultipartFormEncoder() - for part in request.parts { - encoder.addPart(part) - } - let body = encoder.encode() + let body = encoder.encode(parts: request.parts) result.addValue(body.contentType, forHTTPHeaderField: "Content-Type") result.addValue("\(body.contentLength)", forHTTPHeaderField: "Content-Length") result.httpBody = body.data diff --git a/Tests/OsirisTests/MultipartFormEncoderTests.swift b/Tests/OsirisTests/MultipartFormEncoderTests.swift index 62a4d26..1c935e1 100644 --- a/Tests/OsirisTests/MultipartFormEncoderTests.swift +++ b/Tests/OsirisTests/MultipartFormEncoderTests.swift @@ -30,15 +30,14 @@ class MultipartFormEncoderTests: XCTestCase { } func testEncodeNothing() throws { - let body = subject.encode() + let body = subject.encode(parts: []) XCTAssertEqual(body.contentType, "multipart/form-data; boundary=\"SuperAwesomeBoundary\"") AssertBodyEqual(body.data, "--SuperAwesomeBoundary--") } func testEncodeText() throws { - subject.addPart(.text(name: "name", value: "Tina")) AssertBodyEqual( - subject.encode().data, + subject.encode(parts: [.text(name: "name", value: "Tina")]).data, [ "--SuperAwesomeBoundary", "Content-Disposition: form-data; name=\"name\"", @@ -50,9 +49,11 @@ class MultipartFormEncoderTests: XCTestCase { } func testEncodeData() throws { - subject.addPart(.binary(name: "video", data: Data("phony video data".utf8), type: "video/mp4", filename: "LiesSex&VideoTape.mp4")) + let data = Data("phony video data".utf8) AssertBodyEqual( - subject.encode().data, + subject.encode(parts: [ + .binary(name: "video", data: data, type: "video/mp4", filename: "LiesSex&VideoTape.mp4"), + ]).data, [ "--SuperAwesomeBoundary", "Content-Disposition: form-data; name=\"video\"; filename=\"LiesSex&VideoTape.mp4\"", @@ -66,12 +67,15 @@ class MultipartFormEncoderTests: XCTestCase { } func testEncodeEverything() throws { - subject.addPart(.text(name: "name", value: "Queso")) - subject.addPart(.binary(name: "image", data: Data("phony image data".utf8), type: "image/jpeg", filename: "feltcute.jpg")) - subject.addPart(.text(name: "spot", value: "top of the bbq")) - subject.addPart(.binary(name: "video", data: Data("phony video data".utf8), type: "video/mp4", filename: "LiesSex&VideoTape.mp4")) + let imageData = Data("phony image data".utf8) + let videoData = Data("phony video data".utf8) AssertBodyEqual( - subject.encode().data, + subject.encode(parts: [ + .text(name: "name", value: "Queso"), + .binary(name: "image", data: imageData, type: "image/jpeg", filename: "feltcute.jpg"), + .text(name: "spot", value: "top of the bbq"), + .binary(name: "video", data: videoData, type: "video/mp4", filename: "LiesSex&VideoTape.mp4"), + ]).data, [ "--SuperAwesomeBoundary", "Content-Disposition: form-data; name=\"name\"",