Getting Started With Server-Side Swift and Amazon Smoke
Do you find yourself wanting to leverage your Swift skills on the backend and don’t know where to start? In this tutorial, you’ll build a REST API using Server-Side Swift and Amazon Smoke. By Jonathan S Wong.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Getting Started With Server-Side Swift and Amazon Smoke
20 mins
- Getting Started
- Smoke and RESTful API Routing
- Creating a GET Topic Operation
- Creating the Response
- Adding Topics
- Adding Route Handlers
- Defining Errors
- Specifying Operations
- Conforming to Smoke Protocols
- Configuring the Application Server
- Running Your Server
- Creating a POST Topic Operation
- Adding a Response Object
- Combining the Request and Response Objects
- Adding a Route
- Validating Your Data
- Troubleshooting
- Where to Go From Here?
Creating a POST Topic Operation
Create a new Swift file called TopicsPostRequest.swift and add the following code to it:
import SmokeHTTP1
import SmokeOperations
import SmokeOperationsHTTP1
import SmokeOperationsHTTP1Server
// 1
public struct TopicsPostRequest: Codable, Validatable, Equatable {
// 2
public var name: String
public var duration: Int
public func validate() throws {}
}
// 3
extension TopicsPostRequest: OperationHTTP1InputProtocol {
public static func compose(
queryDecodableProvider: () throws -> TopicsPostRequest,
pathDecodableProvider: () throws -> TopicsPostRequest,
bodyDecodableProvider: () throws -> TopicsPostRequest,
headersDecodableProvider: () throws -> TopicsPostRequest
) throws -> TopicsPostRequest {
try bodyDecodableProvider()
}
}
This should look familiar to you by now. In the above code:
- You create a
TopicsPostRequest
. - This request has two properties: the
name
of the topic you want to create and theduration
of time you’ll spend learning this hot topic. - Conform to Smoke’s
OperationHTTP1InputProtocol
.
Adding a Response Object
Next, you need to add the response object. Create a new Swift file called TopicsPostResponse.swift and replace its content with:
import SmokeHTTP1
import SmokeOperations
import SmokeOperationsHTTP1
import SmokeOperationsHTTP1Server
// 1
public struct TopicsPostResponse: Codable, Validatable, Equatable {
public func validate() throws {}
}
// 2
extension TopicsPostResponse: OperationHTTP1OutputProtocol {
public var bodyEncodable: TopicsPostResponse? { self }
public var additionalHeadersEncodable: TopicsPostResponse? { nil }
}
In this code, you:
- Create a new
TopicsPostResponse
to handle the response to POSTing a topic. - Conform to Smoke’s
OperationHTTP1OutputProtocol
, as you did inTopicsGetResponse
.
Combining the Request and Response Objects
Now that you’ve added your request and response objects, add this function at the top of TopicsPostRequest.swift to bind them together.
// 1
func topicsPostOperation(
input: TopicsPostRequest,
context: ApplicationContext
) throws -> TopicsPostResponse {
// 2
let topic = Topic(name: input.name, duration: input.duration)
// 3
context.topicStore.addTopic(topic)
// 4
return TopicsPostResponse()
}
Here’s the walk-through:
- You create an operation that takes
TopicsPostRequest
along withApplicationContext
as input and returnsTopicsPostResponse
as output. - You create a new topic with the
name
andduration
passed in from the request. - Now that you’ve created the new topic, you add it to the
topicStore
. - Return a new
TopicsPostResponse
.
Adding a Route
The next task is to add a route for your new request and response. In ModelOperations.swift, add the following case to ModelOperations
:
case topicPost
Also, in operationPath
, replace:
case .topicGet:
With:
case .topicGet, .topicPost:
To make a POST request to create a topic at the /topics
route, you still need to tell Smoke which operation to use. Still in ModelOperations.swift, add the following to the bottom of addOperations(selector:)
:
selector.addHandlerForOperation(.topicPost,
httpMethod: .POST,
operation: topicsPostOperation,
allowedErrors: [(ErrorTypes.serverError, 500)])
With all of that done — time to build and run.
In Insomnia or another REST client of your choice, create a POST request as follows:
- URL: http://localhost:8080/topics.
- Method: POST.
- Select JSON as the request’s content type.
- Add a parameter
name
for the name of your topic and a parameterduration
for the amount of time you’ll spend learning the topic.
Success! Now you can create new topics in your REST API. Try creating a few and then use the same GET request as before to fetch your topics, which will show you the entries you just created.
ApplicationContext
, and therefore TopicStore
, are re-created each time you restart your server. Topics don’t persist between launches. When implementing your own server, you may choose any kind of persistence mechanism or database to solve this.
Validating Your Data
Validation is as important in back-end development as it is in an iOS app. All requests require that your type conforms to Validatable
. You haven’t implemented any validations yet, so users can add invalid data, like negative durations or topics with no name.
In TopicsPostRequest.swift, add the following in validate()
:
// 1
guard !name.isEmpty else {
throw SmokeOperationsError.validationError(
reason: "Name cannot be empty."
)
}
// 2
guard duration > 0 else {
throw SmokeOperationsError.validationError(
reason: "Duration must be positive."
)
}
- If the name is empty, you throw a
validationError
stating that the name can’t be empty. - Similarly, if the duration isn’t greater than 0, you throw a
validationError
because the duration must be positive.
Build and run again.
This time, in Insomnia or your REST client of choice, pass an empty name in your POST request as follows:
You’ll now see your error message on the right!
Now fix the name parameter, but put in a negative duration as follows:
Awesome! You’ve added error conditions just by implementing the Validatable
protocol!
Troubleshooting
The experience of writing server apps on Xcode still hasn’t caught up to building an iOS app. If you’re getting build errors, try cleaning your project by pressing Shift-Cmd-K and then rebuild your server.
Where to Go From Here?
Download the completed project for this tutorial using the Download Materials button at the top or bottom of this page.
If you want to learn more about Smoke and investigate its sample code, visit the Smoke Framework Git Repo. And see how Amazon is using Smoke in their Server-Side Swift talk.
For an article to help you get started using Server-Side Swift, check out Getting Started with Server-Side Swift with Vapor 4 or check out the awesome book, Server-Side Swift with Vapor.
And for more about working with SwiftNIO, read TCP Server With the SwiftNIO Networking Framework.
I hope you’ve enjoyed this article on using Amazon Smoke with Server-Side Swift. If you have any questions, feel free to leave them in the discussion forum below.