Skip to content

Instantly share code, notes, and snippets.

@adam-fowler
Created May 12, 2025 16:39
Show Gist options
  • Save adam-fowler/15e70d6f408b12ceaa7d306b4f7669f1 to your computer and use it in GitHub Desktop.
Save adam-fowler/15e70d6f408b12ceaa7d306b4f7669f1 to your computer and use it in GitHub Desktop.
MultipartFile upload
import Hummingbird
import MultipartKit
import NIOCore
import NIOHTTP1
import StructuredFieldValues
struct FileUpload: Decodable {
let upload: File
}
struct File: MultipartPartConvertible, Decodable {
let data: ByteBuffer
let filename: String
let contentType: String
var multipart: MultipartPart? { nil }
init?(multipart: MultipartPart) {
self.data = multipart.body
guard let contentType = multipart.headers["content-type"].first else { return nil }
guard let contentDispositionHeader = multipart.headers["content-disposition"].first else { return nil }
guard let contentDisposition = try? StructuredFieldValueDecoder().decode(MultipartContentDispostion.self, from: contentDispositionHeader)
else { return nil }
guard let filename = contentDisposition.parameters.filename else { return nil }
self.filename = filename
self.contentType = contentType
}
}
struct MultipartContentDispostion: StructuredFieldValue {
struct Parameters: StructuredFieldValue {
static let structuredFieldType: StructuredFieldType = .dictionary
var name: String
var filename: String?
}
static let structuredFieldType: StructuredFieldType = .item
var item: String
var parameters: Parameters
}
extension StructuredFieldValueDecoder {
public func decode<StructuredField: StructuredFieldValue>(
_ type: StructuredField.Type = StructuredField.self,
from string: String
) throws -> StructuredField {
let decoded = try string.utf8.withContiguousStorageIfAvailable { bytes in
try self.decode(type, from: bytes)
}
if let decoded {
return decoded
}
var string = string
string.makeContiguousUTF8()
return try self.decode(type, from: string)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment