gRPC and Server Side Swift: Getting Started

Learn how to define an API with gRPC and how to integrate it in a Vapor application. By Walter Tyree.

5 (2) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

Learning the Difference Between gRPC and JSON?

For encoding and decoding data objects, gRPC uses Protocol Buffers.

Unlike the plain text files used by JSON, Protocol Buffers are a binary file type, not human readable. They enable the exchange of smaller payloads, which are more efficient and suitable for low bandwidth use cases.

To get started, you must define gRPC messages and data models in a .proto file.

Working with a .proto File

A .proto file is a text file containing definitions for all your APIs. In this tutorial the domain revolves around Messages and Services. Messages are the data objects that get sent between the client and server. Services define how messages get transported. A .proto file can also have some metadata to help the various code generators.

Most exciting to anyone who has ever struggled with comments in JSON: a .proto file can have comments! It supports both // style and /* ... */ style comments!

Open the todo.proto file in the root directory of the project to explore it a bit. The first line of the file specifies the version of gRPC to use. It looks like this:

syntax = "proto3";

If this line is missing, the gRPC system will assume that you’re using version 2, not version 3. After that, some options will assist the code generator in naming things.

Defining the Services

Next, you’ll see the service definition. The rpc entries will each become a func in the generated Swift code.

// The todos service definition.
service TodoService {
  // Return a list of todos.
  rpc FetchTodos (Empty) returns (TodoList) {}
  // Create a new todo
  rpc CreateTodo (Todo) returns (Todo) {}
  // Delete a todo
  rpc DeleteTodo (TodoID) returns (Empty) {}
}

Adding code to every generated func is how you’ll make the server work. Every rpc must have a request and a response message. That’s why FetchTodos sends an Empty message rather than something like FetchTodos().

Defining the Messages

Here is the message spec for the Todo object:

message Todo {
  optional string todoID = 1;
  string title = 2;
}

This code defines two fields; title and todoID. It also ensures that they’re of type string.

The first field is marked as optional. It won’t have a value until it’s been stored in the database. The code generator keeps track of each field in a message by assigning it a number.

In addition to the string type, a field can be many different scalar types and each language generator will make the appropriate translations. Fields can be enumerations or even other messages. For example, below is the definition of TodoList, which is a collection of Todo instances.

message TodoList {
  repeated Todo todos = 1;
}

The repeated keyword means that the code will generate an array of Todos. You can learn more about the different options in the proto3 language guide.

Google provides many well-known types including: Empty, Timestamp, BoolValue and many more. You can read the documentation to learn about them. Since the homebrew version of protoc isn’t bundled with them, this tutorial uses a custom one. Both strategies, using Google’s or making your own, are common.

Note: As your API evolves, you must never reuse numbers. The gRPC generation code uses the numbers to ensure that different versions of your API stay compatible as much as possible.

Exercising a .proto File With Evans

In a Terminal window, navigate to the root directory of the project. This is the directory that contains the todo.proto file. Launch Evans in REPL mode using this command:

evans repl --host localhost --port 1234 --proto ./todo.proto

You’ll see the Evans prompt, similar to this:

  ______
 |  ____|
 | |__    __   __   __ _   _ __    ___
 |  __|   \ \ / /  / _. | | '_ \  / __|
 | |____   \ V /  | (_| | | | | | \__ \
 |______|   \_/    \__,_| |_| |_| |___/

 more expressive universal gRPC client


todos.TodoService@localhost:1234> 

Even though you don’t have a running gRPC server yet and haven’t generated the gRPC Swift code, Evans uses the todo.proto file to provide information about the services.

Recall from the todo.proto file that you have four messages: Empty, Todo, TodoList and TodoID. The file also defines three services: FetchTodos, CreateTodo and DeleteTodo. Use Evans to inspect these.

Now type the following command in the Evans prompt:

show message

You’ll see the four defined messages, like this:

+----------+
| MESSAGE  |
+----------+
| Empty    |
| Todo     |
| TodoID   |
| TodoList |
+----------+

Now type show service to see the list of services. Evans will show:

+-------------+--------------+--------------+---------------+
|   SERVICE   |     RPC      | REQUEST TYPE | RESPONSE TYPE |
+-------------+--------------+--------------+---------------+
| TodoService | FetchTodos   | Empty        | TodoList      |
| TodoService | CreateTodo   | Todo         | Todo          |
| TodoService | DeleteTodo   | TodoID       | Empty         |
+-------------+--------------+--------------+---------------+

To close Evans and return to Terminal type: exit.

You are on the right track. The next step is to generate some Swift code.

Generating Swift Code From a .proto file

Make sure Terminal is in the directory with the todo.proto file and type the following:

protoc --swift_out=Sources/App/Models/ --grpc-swift_out=Sources/App/Controllers/ todo.proto

This command will create two files: Sources/App/Models/todo.pb.swift and Sources/App/Controllers/todo.grpc.swift. The first is for the Message items, the second is for the Service items. You’ll not be editing these files directly, and whenever the API changes, you’ll need to regenerate them. If the files don’t appear in your IDE, you may need to close and reopen the project to refresh the list of files.

There are a number of other options available but the ones specified above will generate the two swift files for this tutorial.

Note: The grpc-swift plugin does not create async/await code by default and does not yet officially support async/await. One of the options for protoc will generate async/await style code based on a proposed implementation. You can read more about this option and the async/await code at the GitHub repository for the project.