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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

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:

  1. You create a TopicsPostRequest.
  2. This request has two properties: the name of the topic you want to create and the duration of time you’ll spend learning this hot topic.
  3. 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:

  1. Create a new TopicsPostResponse to handle the response to POSTing a topic.
  2. Conform to Smoke’s OperationHTTP1OutputProtocol, as you did in TopicsGetResponse.

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:

  1. You create an operation that takes TopicsPostRequest along with ApplicationContext as input and returns TopicsPostResponse as output.
  2. You create a new topic with the name and duration passed in from the request.
  3. Now that you’ve created the new topic, you add it to the topicStore.
  4. 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 parameter duration for the amount of time you’ll spend learning the topic.

Posting a new 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.

Get posted topics

Note: For simplicity, 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."
  )
}
  1. If the name is empty, you throw a validationError stating that the name can’t be empty.
  2. 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:

Name validation error

You’ll now see your error message on the right!

Now fix the name parameter, but put in a negative duration as follows:

Duration validation error

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.