One of the primary challenges in learning to work with Protocol Buffers is finding an API to communicate with. Adoption is currently not wide-spread and I had trouble finding public APIs willing to communicate via protobufs. So, I decided to create my own API using server-side Swift, thus fulfilling the requirements (tenuously) for calling myself a full-stack developer. I looked at two of the most popular Swift web server frameworks currently available Vapor and Perfect.
Both offer easy setup via assistant tools (Vapor Toolbox and Perfect Assistant, respectively). However, the default projects’ setups are philosophically quite different. Vapor’s default setup is a fully-fledge web server with example HTML files, CSS, communication over multiple protocols, etc. Perfect’s default setup is extremely spartan, relying on the developer to add features as needed. Going head-to-head on documentation, I’d give the slight edge to Vapor, but both clearly explain how to handle requests and responses. Vapor has the reputation for having a larger and more approachable support community if you have questions, but I didn’t engage with either community so I cannot verify this.
Adding Protobufs to either default project is as simple as adding a dependency for it to the Package.swift file and running
.Package(url: "https://github.com/apple/swift-protobuf.git", Version(0,9,29))
Note: At the time of writing, the Swift Protobuf team considers 0.9.29 to be their release candidate, and may soon move the project to a full 1.0 release.
Once that is done, running
swift build in the terminal from the root directory of the project will download the Swift Protobuf library and integrate it with your project. At this point, you’re ready to include the model files created from the .proto definitions. If you are unfamiliar with how to compile .proto files into Swift, I recommend this article as a primer. Once the models are in your
Sources/ directory, you can use them in your request handling code to serialize and deserialize binary messages.
Working with Protobufs
Making a simple API server actually involves gutting the default implementation of both the Vapor and Perfect default projects, which are both set up to serve HTML responses. If you want to send Protobuf data to the server from your client app, you will need to use a POST route, as GET cannot transmit binary data. If you are simply going to request data from the server then GET is appropriate. If you’re receiving data, simply access the body data of the POST request and feed it into the
init(serializedData:) initializer of your Protobuf model object to get copy you can manipulate as you see fit.
To send a Protobuf response to the client app, just follow these general steps:
- Create a new instance of the Protobuf model object.
- Assign values to the properties.
try object.serializedData()to get the Data representation of the object.
- Assign the data to the body of the response.
- Set the
application/octet-stream. (This is optional, but is a good practice.)
- Send the response with a
200 OKresponse code.
The iOS app linked above shows the basics of using Protobufs with URLSession to parse the object(s) being returned by the server.