Uploading a file in SWIFT via POST multipart/form-data

J@y
4 min readNov 18, 2014

Imagine a scenario where you’ve got a PHP based API of some sort. Imagine that one of the endpoints of the API allows you to upload a file (JSON file, image, CSV file, etc…) for further background processing. Then imagine that on the PHP side, the uploaded file’s details are being obtained by using the PHP superglobal $_FILES. Finally, imagine that you’re building a SWIFT-based library (or more correctly module) or app that uses the aforementioned API endpoint.

This is what I was faced with for a while and have been trying to find a solution to. Obviously, one of the things I jumped into when I started this project was to use Alamofire. Alamofire is perfect for getting down to business and not spending time coding all the nitty-gritty one has to deal with when working with APIs. It even offers an Upload method (Alamofire.upload(_, _, _)) which works pretty well, except gets a little complex when needing to perform the type of operation I needed it for.

So I ended up with two solutions. The first one using the straight up networking API offered by SWIFT and once I got that working, I built up the second solution which works with Alamofire. In this post, I will briefly show how I went about both of them.

First, here’s the basic, unassuming and straight-to-the point PHP endpoint we were discussing earlier. Note that this has been greatly simplified for the purpose of this blog post:

testupload.php

POST multipart/form-data file upload with SWIFT networking API

Uploading a file via multipart/form-data means one has to keep in mind a couple of things:

  • A data boundary has to be set: the data boundary is a piece of random string that should not in any occasion whatsoever re-appear within the data being sent to the server as server uses it to figure out where individual data sets begin and end.
  • A Content-Type such as “multipart/form-data; boundary=BoundaryStringGoesHere” has to be set as well.
  • In the HTTP Body of the request, a Content-Disposition as well as mime type of the file being uploaded need to be set as well.

In the code below, I define the data boundary as a constant string that I set but really, the best would be to have this being randomly generated by a function you define somewhere. In UploadNative(), we create a function that uploads a file which path’s has been provided:

UploadController.swift

Running the code below will easily upload the contents the specified file to the http://testapi.example.com/testupload.php endpoint. I ended up going the “native” way because I could not figure out how to do this with Alamofire. Here’s a quick code snippet (more like an XCTest really) which shows how one could use the UploadNative(_, _) method:

UploadControllerTests.swift

POST multipart/form-data file upload with Alamofire library

Right, the principles discussed earlier apply here as well. And I am being a lazy blogger. But the point is to show that this is equally doable with Alamofire, should one desire to do so. There seldom is documentation on this around the Web, which again makes it rather important to share with you guys. When working with Alamofire, I prefer working with routers; and the reason for doing so will not be directly apparent in the current post. However, in the very near future, I shall spend more time detailing the reasons behind such preference. In the meantime however, let’s march on. We will start by creating a router as follows:

Router.swift

As you can see, the bulk of the work in creating the request is done in the Router. If one pays attention, one realizes that whereas previously we were concatenating strings, here we are directly working with instances of NSMutableData or NSData. This is to demonstrate that it is possible to do it both ways and I am quite confident that going the NSData.appendData() way would be the most recommended, mostly when dealing with pieces of data that need to be uploaded and that are not the text mime type.

We will now proceed to use our Alamofire-based router to perform a file upload. For this, we have added an UploadWithAlamofire(_, _, _) method which looks as follows:

UploadController.swift with UploadWithAlamofire method

As it can be seen, the code is much more succinct and to the point and it works! It really took me a while to figure this out. Using Alamofire.upload() simply did not work for this kind of situation. Let’s add some code to our previous XCTestCase to show how our brand new Alamofire-based method can be used:

UploadControllerTests.swift with UploadWithAlamofire test

And voila! We’re done! It is important to note that I am pretty new at coding using SWIFT and that the provided code may not be perfect. More can and should be done. For example, the boundaries should be auto-generated. The file that is being uploaded mime type should be obtained programmatically and a few other things. However, the objective of this post was not to dive into it all but to quickly show how to create multipart/form-data file uploads in SWIFT.

All code used in this post can be found here.

PS: Updated the code to be compliant with the changes from Xcode 6.1.

Originally published at creatvwithin.blogspot.com on November 18, 2014.

--

--

J@y

Technology, lifestyle, travel and food enthusiast.