Swift on Server: making an API Call
A small tutorial demoing how to use Swift on server with Vapor framework for making request to another REST Service.
Don’t try the classic way using URLSessions, they are not yet implemented on Linux, but luckily Vapor’s creators took care of it and made it very easy to do it.
Requirements
You must have Swift and Vapor toolkit installed. If you is not the case, check my tutorial.
Create a new project
1 |
$ vapor new apigetdemo |
Build the project
1 2 |
$ cd apigetdemo $ vapor build |
Create an Xcode project
If you’re on a Mac and want to use Xcode
1 |
$ vapor xcode |
and open it.
Otherwise just use your favourite editor to open the apigetdemo
folder.
Make a new route
Open the main.swift
file from the Sources/App
folder, delete the posts
route and create a new get route temperature
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import Vapor let drop = Droplet() drop.get { req in return try drop.view.make("welcome", [ "message": drop.localization[req.lang, "welcome", "title"] ]) } drop.get("temperature") { req in return "Montpellier temperature is: <todo> °C" } drop.run() |
Build & run
For testing the new route:
1 |
$ vapor buil && vapor run |
then in a browser go to url: http://localhost:8080/temperature
You should get in return: Montpellier temperature is: <todo> °C
Prepare to make the API call
For that I’ll use a service exposed by openweathermap.org.
You must register and get you own API key (APPID) to make the calls to this API.
The GET request we’ll make will be:
http://api.openweathermap.org/data/2.5/weather?q=Montpellier,FR&units=metric&APPID=<apppid>
(replace <appid>
with your own id)
and in return we’ll get a JSON like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "coord":{ "lon":3.88, "lat":43.61 }, "weather":[ { "id":800, "main":"Clear", "description":"clear sky", "icon":"01d" } ], "base":"stations", "main":{ "temp":13.24, "pressure":1018, "humidity":44, "temp_min":13, "temp_max":14 }, "visibility":10000, "wind":{ "speed":4.6, "deg":290 }, "clouds":{ "all":0 }, "dt":1488367800, "sys":{ "type":1, "id":5588, "message":0.0026, "country":"FR", "sunrise":1488349206, "sunset":1488389635 }, "id":2992166, "name":"Montpellier", "cod":200 } |
You can also use your own or the free one like jsonplaceholder one: https://jsonplaceholder.typicode.com/todos/4
that returns:
1 2 3 4 5 6 |
{ "userId": 1, "id": 4, "title": "et porro tempora", "completed": true } |
Make the API call
For that we’ll gonna use Vapor’s Droplet.client
that makes requests to remote servers. In this exemple we’ll only use a simple GET request, but take a look at the documentation you can do more complicated requests as well.
Modify the temperature
route in main.swift to look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
drop.get("temperature") { req in //service URL let URL = "http://api.openweathermap.org/data/2.5/weather" //the query data let QUERY = "Montpellier,FR" //the APPID to use with openweathermap service let APIKEY = "XXXX" //make the query with passing the query params let response = try drop.client.get(URL, query: ["q": QUERY, "APPID":APIKEY, "units":"metric"]) print(response) return "Montpellier temperature is: <todo> °C" } |
In the console you can see the response and in the body the response as JSON:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "coord":{ "lon":3.88, "lat":43.61 }, "weather":[ { "id":800, "main":"Clear", "description":"clear sky", "icon":"01d" } ], "base":"stations", "main":{ "temp":13.75, "pressure":1017, "humidity":47, "temp_min":13, "temp_max":14 }, "visibility":10000, "wind":{ "speed":5.1, "deg":310 }, "clouds":{ "all":0 }, "dt":1488369600, "sys":{ "type":1, "id":5662, "message":0.0167, "country":"FR", "sunrise":1488349204, "sunset":1488389636 }, "id":2992166, "name":"Montpellier", "cod":200 } |
Getting the temperature from the result
Looking at the JSON’s response you can see we just need the “temp” that’s in the “main” object.
So we get the temperature
using:
1 2 3 |
guard let temperature = resp?.data["main", "temp"]?.string else { return "Temperature inconnue pour Montpellier" } |
The final result
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
drop.get("temperature") { req in //service URL let URL = "http://api.openweathermap.org/data/2.5/weather" //the query data let QUERY = "Montpellier,FR" //the APPID to use with openweathermap service let APIKEY = "XXXX" //make the query with passing the query params let response = try drop.client.get(URL, query: ["q": QUERY, "APPID":APIKEY, "units":"metric"]) return "Montpellier temperature is: \(response) °C" } |
Extra
An exemple with handling a result that contains a list of items.
For that we’ll get a list of todo items from:
https://jsonplaceholder.typicode.com/todos/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[ { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }, { "userId": 1, "id": 2, "title": "quis ut nam facilis et officia qui", "completed": false }, { "userId": 1, "id": 3, "title": "fugiat veniam minus", "completed": false }, ... ] |
We just want to keep a list of titles from that answer:
1 2 3 4 5 6 7 8 9 10 11 |
drop.get("list") { req in let URL = "https://jsonplaceholder.typicode.com/todos/" let resp = try? drop.client.get(URL) guard let list = resp?.data["title"]?.array?.flatMap({$0.string}) else { return "Not an array" } //print as json return try JSON(node: list.makeNode()) } |
It’s that easy, thanks to Vapor framework.