Creating and deploying a Vapor (Swift) web app into Heroku cloud platform — Part (1/2)
Intro
This is the first of a serie of 2 articles:
The first article approaches how to Deploy on Heroku cloud platform a web app built using Vapor.
The second article is the natural evolution of this one, and we will improve our web app to deal with more complex HTTP methods (GETs, dynamic routing, POSTs…), and also integrating a PostgreSQL database.
Before we start, and if you’re not familiar with Heroku and Vapor,
Heroku is a cloud platform as a service (PaaS) supporting several programming languages, and Vapor is an open source web framework written in Swift that can be used to create RESTful APIs, web apps, and real-time applications using WebSockets.
I — Creating a web app using Vapor.
Installing Vapor on macOS.
Vapor can be installed using brew package manager, just by executing on macOS Terminal:
$ brew tap vapor/tap
$ brew install vapor/tap/vapor
More details or options about how to install Vapor on macOS can be found here.
Creating a Vapor web app.
Now that Vapor is installed we will create our first project. Lets say you want your project to be named MyFirstWebApp
, execute on macOS Terminal:
$ vapor new MyFirstWebApp
Note: During the install, you will be asked if you want to include in your project the Leaf framework (for easy-to-use dynamic HTML) or the Fluent framework (ORM for easy-to-use databases). You can include Fluent since we will be using it next tutorial. About Leaf, you can skip it.
The vapor new MyFirstWebApp
command created a folder with a brand new template project. Let see how it looks:
$ cd MyFirstWebApp
$ open Package.swift
After opening the project, and once the Swift Package Manager dependencies have finished downloading, click the play button to build and run your project.
Open your web browser, and visit localhost:8080 or http://127.0.0.1:8080
More information about how to create your first web app can be found here.
II — Creating an Heroku web app dyno/container
Creating an Heroku app dyno/container
Go to Heroku dashboard at https://dashboard.heroku.com/apps (you must be registered) and create a new app.
(Friendly note: you can have 5 apps for free)
Adding buildpack
Buildpacks are scripts that run when your app is deployed. They are used to install dependencies and configure your environment.
Saying so, on you app settings, we will need to add the Vapor buildpack. Just add the following url :
https://buildpack-registry.s3.amazonaws.com/buildpacks/vapor/vapor.tgz
(Friendly note: you can also add Vapor build pack via Heroku CLI)
More info about buildpacks can be found here and here
III — Deploy your web app into Heroku
Installing Heroku CLI
There are several ways to deploy your code into Heroku. Connecting to your GitHub is provably the simplest way, but using Heroku CLI is provably the most useful on a long run because makes it easy to create and manage your Heroku apps directly from the terminal,
To install Heroku CLI execute on macOS Terminal:
$ brew tap heroku/brew && brew install heroku
After you install the CLI, run the heroku login
command. You’ll be prompted to enter any key to go to your web browser to complete login. The CLI will then log you in automatically.
More info about Heroku CLI can be found here.
Deploying app using Heroku Git
After Heroku CLI is installed and you login, we need to link your app source code with the your app Heroku git repository (and push the changes). To do so, inside your project folder, execute on macOS Terminal:
$ heroku git:remote -a my-first-vapor-web-app
$ git add .
$ git commit —m ‘first commit!’
$ vapor heroku push
Note that my-first-vapor-web-app
was the name we gave our app on the beginning of this chapter.
Deploying app using Heroku Git : trouble shooting
As reported here you will face the following error:
remote: error: missing LinuxMain.swift file in the Tests directory
You can either (for now) just comment the test target on your Package.swift
file as showed bellow…
or passing the --enable-test-discovery
build flag via Heroku configuration and attempting to deploy again.
$ heroku config:set SWIFT_BUILD_FLAGS="--enable-test-discovery"
$ git commit -m "Enable test discovery on Heroku" --allow-empty
$ vapor heroku push
PROCFILE
Everything looks good, we have deployed our code with success, but when we try to test…
Happens that Heroku apps must include a Procfile.
A Procfile is a file that specifies the commands that are executed by the app on startup. Is always a simple text file that is named Procfile
without a file extension.
We can create our Procfile by executing on macOS Terminal:
$ echo "web: Run serve —-env production --hostname 0.0.0.0 —-port $PORT" > Procfile
About our Procfile:
web
states that our dyno is a web app,Run serve
will start our web app in production environment mode (--env production
),—- hostname 0.0.0.0
states that your app host ip will be assigned by DHCP. More info (here)- Our web app listening port (
--port $PORT
) is a config var. You can find config vars section on your app settings (See Image 9). If you don’t implicitly assign a port of your preference, Heroku will choose one; still is recommended to set the port on your Procfile.
More information about your Procfile can be found here (highly recommended reading).
One last push (after adding Procfile)…
$ git add .
$ git commit -m "Added Procfile"
$ vapor heroku push
And our first Vapor web app was successfully deployed on Heroku and is ready to serve.
IV — Extra notes
Scale up
Once you’ve built successfully, you need to add at least one server, one web is free and you can get it with the following:
$ heroku ps:scale web=1
Logs
A quick way to troubleshoot problems is checking your app logs using heroku logs --tail
or and then look for the error meaning here.
References
- Vapor docs : What is Heroku
- Heroku error: Your account has reached its concurrent build limit
- Heroku Logs — The Complete Guide
Materials
All the materials used can be found at here.
V — Next?
On the next article of this series (available at 8 Jan 2021), we will improve our web app with some utilities, and learn to deal with more complex HTTP methods (GETs with dynamic paths, POSTs) and how to integrate a PostgreSQL database.