CRUD operations with Vapor 3

Aditya Shinde
The Startup
11 min readMay 30, 2020

--

In the last article, we got started with Vapor, checked how to create a new project, and tried to understand the project structure. In the last article, we had used the SQLite database. You can check the last article here.

In this article, we’ll use the PostgreSQL database, We’ll also learn how to add a new table in the database and then we’ll perform CRUD operations on the table.

Let’s create a new project named CRUDOperations.

Install PostgreSQL

If PostgreSQL is not installed on your Mac, please refer to this link for installation.

Create Database for Project

After installation is finished open the terminal and hit command psql. Your terminal should look like following

After hitting psql command on terminal

To create a new database, the command is CREATE DATABASE followed by database name and semicolon (;). I’ll name the database the same as we’ve named project that is ‘crudoperations’. So hit following command in the terminal now.

CREATE DATABASE crudoperations;

If your terminal looks like following, your database is created

Create database

Configure project to use PostgreSQL

1. Update Package.swift

When we create a new Vapor project, by default it uses the SQLite database. To use the PostgreSQL database, we have to change the dependencies in Package.swift file.

Package.swift

Package.swift

Check the code changed under comment 1 & 2

  1. In dependencies, we changed our fluent ORM from SQLite to PostgreSQL.
  2. In targets for app target, we changed dependency from FluentSQLite to FluentPostgreSQL.

Now on terminal run following command

vapor xcode

This command will install the dependencies we’ve added in the Package.swift file.

2. Update configure.swift

We have to update code in the configure function of the configure.swift file. I’ve added numbers in the comments in code. Let’s discuss them in detail.

  1. We’ve decided to use the PostgreSQL database so we’ve to import is ORM FluentPostgreSQL here.
  2. We have to register the FluentPostgreSQLProvider. So we are replacing FluentSqliteProvider with this one.
  3. As we are not using SQLite any more, the line where I’ve added 3rd comment, I’ve commented it for reference, you can remove it.
  4. We have to create PostgreSQLDatabaseConfig where our hostname would be localhost, the port would be 5432, the username would be your machine user name, database name would be CRUDOperation which we had created.
  5. In comment 5 line, we create an object of PostgreSQLDatabase with the help of the config.
  6. In comment 6 we add our database object in databases.
  7. As I had mentioned in the last article, we use migrations to add or alter the tables in the database. In comment 7, I am adding a table named Pet in the database. At this moment this line with show error because we have not created a model named Pet yet. It would be resolved once we create it.

3. Remove unwanted files

We won’t be using Todo.swift and TodoController.swift files. We will be creating our model and controller. Remove these two files from the project navigator. Refer following image

Remove these two files

Once these files are removed, go to routes.swift file and remove the code written to add routes and call functions from TodoController. You have to remove the code written under the comment

// Example of configuring a controller

4. Create a new model for table Pet

Create a new swift file named Pet.swift in the group Models. Once the file is created, write the following code into the file. Now if you run the code, it won’t show any compilation error.

Let us understand the code in Pet class step by step

  1. In the last article, we’ve already discussed that Fluent is ORM provided by Vapor. We are using the PostgreSQL database for this project. That is why we are importing the FluentPostgreSQL module here.
  2. Whatever tables we’ll need in the project, we’ll be creating those as classes in our code. For table Pet, here I’ve created class Pet. I’ve made this class ‘final’ so that it won’t be inherited. And it shouldn’t because it is representing one of the tables in our database. I’ve confirmed protocol PostgreSQLUUIDMdel, because I want our Pet must have a unique identifier and it should be of type UUID. In case you want id should be of type int, you have to confirm PostgreSQLModel protocol instead.
  3. Here I am declaring the properties of my class. In other words we are specifying the columns of our table. I’ve declared id as optional because id would be automatically generated whenever new entry would be added to the table. Fluent will take care of that. Then I’ve declared other properties like type, breed, and name.
  4. Here, I’ve written the constructor for our class. Constructor doesn’t accept anything for id because as I mentioned in step 3, id is optional, and Fluent will generate it automatically for us.
  5. I’ve confirmed the Parameter protocol with our class. If you want any web service to use Pet as a dynamic parameter in the URL, this will take care of that. We’ll learn more about this in upcoming articles.
  6. I’ve confirmed the Content protocol with our class here. As I’ve mentioned in the last article, Content is a superset of the Codable protocol we use in iOS coding. Content helps us to convert our models to JSON when we have to return the output of our web services and vice versa.
  7. I’ve confirmed the Migration protocol here. Migration helps us to alter the table whenever we need it. If we need to add a new column in the table or we want to delete any column from the table, we’ll be writing that code here. We’ll learn how to do this in the future.

5. Postico

Now run the app ins Xcode and our table is ready. If you want to check the table, you can download Postico. Postico is a PostgreSQL client for Mac. Once you download and open it, you’ll see the following window.

Postico

Click on the edit button. It will ask you to fill some information. It is the same information we have provided in the config.swift file while creating PostgreSQLDatabaseConfig. Check the following image.

Database configuration information

Once you provide all the information like above, click on connect. It will open the database. You’ll see two tables, Fluent and Pet.

Pet table is created.

Isn’t it easy to create tables with Vapor? If you open the Pet table now, it would be empty.

6. PetController

Now as our table is created, it is time for us to write web services, which will write and read data from the table. For this create a new swift file in the Controllers group and name it ‘PetController.swift’. We are going to write all the web services in this class which are related to the Pet table.

Everything is set now. So let the CRUD begin.

CRUD

1. Create

Write the following code in ‘PetController.swift’.

PetController.swift
  1. We have written this function to add a new Pet in our pet table. The function takes the HTTP request as a parameter and returns an object of Pet class. In other words, it returns the JSON object of Pet. We can see there something written as the Future. Just to elaborate this first we have to understand that Vapor is a completely asynchronous framework. Multiple requests received at the server, performed on a separate thread. That means the function doesn’t need to return the object of Pet immediately. The server might be busy performing some other operation. But this return type ‘Future<Pet>’ specifies that the function ‘createNewPet’ returns Pet object soon.
  2. We’ll be passing a JSON object which will contain pet data like type, breed, name (everything excluding id, which will be automatically generated), in POST request. In step 2 we decode the JSON to Pet object and flatMap it to get the pet object which we’ve received from the request. A small note, we can decode JSON data received in the HTTP request as Pet object because we’ve confirmed the ‘Content’ protocol with our Pet class. As it is already mentioned above, Content is a superset of the Codable protocol of swift.
  3. In the flapMap closure, we get the data which we’ve received from the request in Pet model’s object and now with the function ‘save’, we are storing into Pet table as a new record. ‘save(on:_)’ returns the same model which is passed as an argument.

Route

Now we’ve to add an HTTP method and an URL with which we can call this create pet web service. Add the following code in ‘routes’ function of the router.swift file.

Route to create new pet
  1. We have created an object of PetController class
  2. We’ve specified that the router will use the HTTP post method, it’s path component is a pet. That is the end URL for this would be ‘http:/localhost:8080/pet’ and it has to trigger ‘createNewPet’ function of PetController.

Now run the project in Xcode and let us test create operation with ‘Postman’.

In postman paste the above URL in the textbox, select the POST method and in Headers, add Content-Type, ‘application/json’. It should look like following

Content-type should be application/json

Then in Body tab add JSON data with your desired values like in the following image, I’ve added name as Tom, the breed is Lab and type is Dog.

Pet data

Once all this is done, click on send button and in response, you should be able to see the same pet data you’ve passed along with id, like the following image

Web service response

You can verify this by checking if the table is having this entry. To check this, open the Pet table in Postico, you should see something like the following.

First pet entry in the table

Like this, you can add some more pets to the table.

2. Read

Now we have some data in our database. We’ll try to read that data now. We’ll write a web service that will fetch(read) all the pet records from the pet table.

Get all pets
  1. We’ve written a function named ‘getAllPets’ which accepts HTTP request as a parameter and returns an array of Pet objects with Future.
  2. We query on the Pet table with request and call function named ‘all’ which returns an array of the model on which we are querying.

Route

Add the following lines in the ‘routes’ function of routes.swift file

Route to get all pets

We’ll use the HTTP GET method. The path component would be the same as that is a pet. So the final URL won’t change. And we are using ‘getAllPets’ function of PetController.

Now run the project in Xcode and test the new function in postman. You should be able to see output similar to the following.

Get all pets

3. Update

To perform an update, we’ll use the HTTP PUT method. We need to identify the pet which wish to update with some unique property. In our case id is that property. I’ve a dog in my pet table named ‘Tom’. I want to update its name as ‘Tomas’. For this first add following function into PetController.swift

Update pet
  1. We’ve created a function named ‘updatePet’ that accepts HTTP request as a parameter and returns Pet object with updated data.
  2. In this case, we’ll be appending the ‘id’ of the pet which name we wish to update. We’ll also be passing JSON with updated pet data with the request. That is why when we flatMap in this step, first we get the pet object which id we’ve added in the URL with the help of parameter protocol. We’ll get one more pet object which we are decoding here from the pet JSON we are passing with updated pet data. That is why I’ve named them as ‘pet’ and ‘updatedPet’ in the closure parameters.
  3. In step 3 we update all the data of the pet which we are getting. We are doing updations with pet object because it contains the ‘id’ of the pet against which we’ll be updating the data.
  4. Here we save the pet object in the table with updated data.

Route

Route for this web service will be a bit different. Add following code in the route function

Router for update pet

Here the URL will remain the same as we’ve added pet as path component but, I’ve written Pet.parameter as path component as well. As mentioned above I’ll have to append the pet id in the URL. And at the end we are using the updatePet function of the PetController. Now run the code and test it with Postman. The request and response should look like the following.

Update pet

Here you can clearly see that I’ve appended the pet id in URL. And in body, I’ve updated the name as ‘Tomas’ and in output, you can see that. For more clarification, you can check the same in the table with the help of Postico.

4. Delete

To delete the user we’ll use the HTTP DELETE method and again alike update, we’ll pass the pet id in the URL. Add following function to PetController.swift

Delete Pet
  1. We’ve created a function named ‘deletePet’ which accepts HTTP request and return HTTP status.
  2. We get the pet from the table with the help of parameter we’ve appended on URL
  3. We delete that pet with the help of delete function
  4. Here we transform the result with HTTP status because delete function returns nothing.

Route

Add following lines in routes function

Route to delete pet

It is almost the same as the update one, the only change is we change the method to delete instead of put.

That’s it

Yes. That’s it. Isn’t it very simple with swift to write web services :)

Summary

We started learning how to create a database with PostgreSQL. Then we added the required dependencies in Package.swift. We updated configurations for PostgreSQL. We created a pet table in the database and then with the help of PetController, we performed the CRUD operations.

You’ll be able to get the whole code here.

Where to go from here

In the next article, we’ll learn to provide filtered and sorted the responses. We’ll learn to add validations and also we’ll learn to encrypt and decrypt the data.

Till then

--

--

Aditya Shinde
The Startup

A Swift enthusiast. Very curious about new trends in technology.