There are lot of server side swift frameworks. The popular frameworks on GitHub are Perfect, Vapor, Kitura.
We will Create a small todo app using Postgres database, Will see how to implement simple routes and basic CRUD operations using Vapor framework.
Vapor :
This is the second most popular framework on GitHub for swift. Vapor provides best documentation and it build in swift3. And it will be a great staring point to start server side swift. Vapor had all the packages that needed by an app and it has a very supporting community.
Reasons to use vapor :
- Vapor uses web sockets to make real-time connections.
- JSON Serialisation
- Ability to create Controllers and Models.
- Extensible, It uses Middlewares to add any parameters to HTTP requests. and we can add more functionalities
- Expressive, The static type system allows you to write less and do more
Before getting started we need have these things
- Mac running on latest Os(Mac OS 10.12, Sierra)
- Xcode 8 or above
- Basic understand of swift language and iOS SDk
Getting started
Install Xcode : Install Xcode from App store
Install Vapor :
- Compatibility Check : To check that your environment is compatible run the following script in terminal
-
1curl -sL check.vapor.sh | bash
If you get the green check mark, then you are all set to install vapor - Install vapor toolbox : Run the following command to install Vapor
1curl -sL toolbox.vapor.sh | bash
it might take a while. and finally we will get the message Vapor Toolbox v1.0.5-4-gd20c424 Installed - To check Vapor is working, just type the vapor command in your terminal and it will display like this
Install Postgres : The easiest way to install Postgres is through Homebrew. If homebrew is not installed, download it from the link. Install Postgres using this command
1 |
brew install postgres |
Type the following command, to ensure that you have downloaded postgres
1 |
psql --version |
Starting a new vapor project :
We a building a simple todo app which can add, update and delete a todo. We will give api’s to do basic crud operations. Open terminal, And Cd to the directory of your choice and type the command.
1 |
vapor new Todo |
This will create a new Todo Project
The directory will look like this
vapor creates a the Package.swift, here we can add any dependencies for the project. Then in the App folder, we can see main.swift, Controllers and Models.
The main.swift file is our main app file, where we can initialise and run the server
The resources folder contains the views, which contains and html and template files.
We can easily create Xcode project using vapor toolbox. Go to project directory type the command
1 |
vapor xcode |
This command will fetch the dependencies for the project and will take some time. After fetching all the dependencies it will ask you to open project in Xcode, type y and enter to open the project in Xcode
In Xcode project navigate to Source/App/Main.swift
We can see the code like this
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import Vapor let drop = Droplet() drop.get { req in return try drop.view.make("welcome", [ "message": drop.localization[req.lang, "welcome", "title"] ]) } drop.resource("posts", PostController()) drop.run() |
This main.swift file imports the Vapor framework, and initiates the Droplet
Droplet, is a service that have access to Vapor functionalities. It is backbone of our server and it responsible for running server . So we import the vapor in main.swift and created an intense of droplet.
1 2 3 |
import Vapor let drop = Droplet() |
The droplet will handle many properties, get the documentation from here
Create a route: Now create a route, a get request which returns the list of todos and finally run the drop.
1 2 3 4 5 6 7 |
drop.get(“todos”) { request in return try JSON(node: [“todos”: [[“title”: "test", “description”: “test description”], ["title": “another”, "description": “another desc“]] ]) } drop.run() |
Now run the Xcode project, make sure that you have selected app schema.
Run the application from Xcode to get the app running on localhost on port 8080. After Successfully building and running the app in Xcode. you can see Server ‘default’ starting at 0.0.0.0:8080 in logs
Now open the browser or post man and navigate to http://localhost:8080/todos, we can see the list of todo’s
Create a Todo model :
Its good to have a Todo model, to avoid hard coding values. Vapor is providing model protocol, this will help us to convert models to JSON easily
vapor framework includes Fluent framework, which is ORM tool for swift that will work with different databases.
Cerate a file Todo.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import Foundation import Vapor struct Todo: Model { var exists: Bool = false var id: Node? let title: String let description: String } init(title: String, description: String) { self.title = title self.description = description } |
The first property we will set is Id, this property will contain the identifier when model is fetched from DB, if it is nil it will set after when we save to DB.
Node Initializable :
we need to create a model from persistence data, model uses NodeInitializable to archive this data.
1 2 3 4 5 |
init(node: Node, in context: Context) throws { id = try node.extract("id") title = try node.extract("title") description = try node.extract("description") } |
Node Representable :
NodeRepresentable will help us to save it back to database
1 2 3 4 5 |
func makeNode(context: Context) throws -> Node { return try Node(node: ["id": id, "title": title, "description": description]) } |
Preparation :
We need to create a table for our Todo class, we will crate table using this prepare method. here we have created the todos Table .
1 2 3 4 5 6 7 |
static func prepare(_ database: Database) throws { try database.create("todos") { todo in todo.id() todo.string("title") todo.string("description") } } |
Revert :
this is the reversion of prepare method, this will be run using this command
1 |
vapor run prepare --revert |
1 2 3 |
static func revert(_ database: Database) throws { try database.delete("todos") } |
Here it will delete the table todos.
Now we have seen how to create a route and model. Lets connect to Postgres database to create more routes
Setting up Postgres:
- add the postgres provider url to Package.swift file
-
1234567891011121314151617import PackageDescriptionlet package = Package(name: "TodoModule",dependencies: [.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 5),.Package(url: "https://github.com/vapor/postgresql-provider", majorVersion: 1, minor: 0)],exclude: ["Config","Database","Localization","Public","Resources",])
- Regenerate Xcode project to download the postgres dependencies
- Import the VaporPostgreSQL in main.swift file,
1import VaporPostgreSQL - Append the Todo.self to drop preparation so that we can use model with Database
1drop.preparations.append(Todo.self) - Then add provider to droplet so that database is available
12345do {try drop.addProvider(VaporPostgreSQL.Provider.self)} catch {assertionFailure("Error adding provider: \(error)")}
- Create a configuration file for Postgres, create the following file: Config/secrets/postgresql.json and update the file with these values, use your own username for “user”
1234567{"host": "127.0.0.1","user": "afsara","password": "","database": "todos","port": 5432} - Creating Postgres Database, Run the Postgres server locally by using this command
1postgres -D /usr/local/var/postgres/- Open another terminal and Create the database using this command
1createdb todo - Type psql <Table name> command to get Postgres command line interface. Now we can check out routes by using postman. and plsql commands
- Open another terminal and Create the database using this command
Now we will create routes, which will perform the CRUD operations
AddTodo Route:
Now we are creating Add todo route using Postgres for adding todo and saving it to DB
1 2 3 4 5 |
drop.post("todo") { req in var todo = try Todo(node: req.json) try todo.save() return try JSON(node: ["Success": "Todo Added"]) } |
In this route, we have created a new instance of todo from request (req.json), which is passed from post request.
Save that created instance using save() command.
This is post route is expecting body like this
1 2 3 4 |
{ "title": “New Todo“, "description": "New Todo details“ } |
GetTodo By ID Route :
1 2 3 4 5 6 |
drop.get("todo", Int.self) { req, todoID in guard let todo = try Todo.find(todoID) else { throw Abort.notFound } return try todo.makeJSON() } |
Here, Int.self 2nd argument in the path so the url will be todo/1, so that we can send parameters in route.
We are using Fluent, So We can Easily use find(_:) , to get the instance of model
UpdateTodo By ID Route:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
drop.post("updateTodo", Int.self) { req, todoID in guard var todo = try Todo.find(todoID), let updatedTitle = req.data["title"]?.string, let updatedDesc = req.data["description"]?.string else { throw Abort.badRequest } todo.title = updatedTitle todo.description = updatedDesc try todo.save() return try todo.makeJSON() } |
This is the route to update todo by using its Id. Here we will get id by Int.self and request parameters. We are getting the instance by using ID, and updating values in it and saving back to DB.
Delete Todo Route :
1 2 3 4 5 6 7 8 9 10 |
drop.delete("todo", Int.self) { req, todoID in guard let todo = try Todo.find(todoID) else { throw Abort.notFound } try todo.delete() return try JSON(node: ["Success": "Todo deleted"]) } |
Here we are finding the model by using id and deleting it from DB.
Conclusion :
In this tutorial we covered, how to install vapor, Xcode, Postgres and Created API’s For Simple CRUD operations. This server side swift is new technology and actively being developed by IBM, perfect an vapor teams.
This post will help to getting started with server side swift with Vapor.