Recently, I started delving into the Hanami framework which version 2 had been released a couple of months ago. Since I got to know Docker and Docker Compose, I use them over and over again because they help with running varied services on my machine without installing required dependencies, etc. If you don’t know them yet, I really encourage you to become acquainted with them. I find them highly convenient and I would like to use them also for setting API service connected with a relational database, in my case, it will be PostgreSQL. Let’s get the show on the road.
First of all, we have to make sure that the ruby version that we use is at least in version 3.0.0. That requirement is constituted by Hanami. To begin, we have to install the
gem install hanami
Once it’s done, let’s create a new Hanami application from the scratch.
hanami new simple-api
This process created a bunch of files inside of the directory that follows the name of applications that we provided in the previous command. In my case it’s
Now, we need to create Dockerfile to specify the runtime environment for our application.
# simple_api/Dockerfile.dev FROM ruby:3.2.1-alpine WORKDIR /usr/src/app COPY Gemfile Gemfile.lock ./ RUN apk update && apk add --no-cache build-base ruby-dev RUN bundle install EXPOSE 2300 COPY . .
We are going to use
ruby:3.2.1-alpine image to avoid using an overloaded ruby image but there is required to install two libraries to make it work:
ruby-dev. If you are familiar with Rails, you might know the port number 3000 which is widely used, in the case of Hanami applications the default port is 2300. Once the Dockerfile is ready, we can build an image
docker build -t simple-api -f Dockerfile.dev .
Everything looks good, so we can jump into a docker-compose file.
# simple_api/docker-compose.yaml version: '3.8' volumes: postgres-data: services: db: image: postgres volumes: - postgres-data:/var/lib/postgresql/data env_file: .env app: image: simple-api command: sh -c "hanami server" ports: - "2300:2300" depends_on: - db env_file: .env
What we specified here is the
db service that is PostgreSQL database and our web application server -
app. Image naming is pretty straightforward, as you could notice ports as well. We are going to use the default port number. In addition, we have to add
POSTGRES_PASSWORD environment variable to the
.env file, in my case:
# simple_api/.env POSTGRES_PASSWORD=XYZ123QWE
Let’s run our containers by running
Awesome, everything looks good but there is still one important thing to do, we have to connect
simple-api web server with postgres. In the beginning, let’s add a few gems to the Gemfile.
# simple_api/Gemfile gem "rom", "~> 5.3" gem "rom-sql", "~> 3.6" gem "pg"
Next we have to add
postgresql-dev library to the
Dockerfile.dev file so that it can successfully install the
pg gem. The line from the file should look like below:
RUN apk update && apk add --no-cache build-base ruby-dev postgresql-dev
Let’s stop containers, rebuild the image, and run containers again. Before we start connecting the API application with the database server, we can create a database. We have to connect to
psql on the database container and call SQL statement, so:
docker-compose exec db psql -U postgres CREATE DATABASE simple_api_development;
Now it’s time to get a closer look at Hanami framework itself because we have to add a persistence provider. We are supposed to create the following file:
# simple_api/config/providers/persistence.rb Hanami.app.register_provider :persistence, namespace: true do prepare do require "rom" config = ROM::Configuration.new(:sql, target["settings"].database_url) register "config", config register "db", config.gateways[:default].connection end start do config = target["persistence.config"] config.auto_registration( target.root.join("lib/simple_api/persistence"), namespace: "SimpleAPI::Persistence" ) register "rom", ROM.container(config) end end
target["settings"].database_url refers to an environment variable with
DATABASE_URL name, let’s add
DATABASE_URL=postgres://postgres:XYZ123QWE@db:5432/simple_api_development to the
# simple_api/.env DATABASE_URL=postgres://postgres:XYZ123QWE@db:5432/simple_api_development POSTGRES_PASSWORD=XYZ123QWE
Unfortunately, that’s not everything, we have to also add the
database_url setting to the
# simple_api/config/settings.rb module SimpleAPI class Settings < Hanami::Settings setting :database_url, constructor: Types::String end end
Now we can rebuild our
simple-api image and restart containers.
Let’s prove that the connection is established and we can use the DB. We are going to create a table, insert sample data, and try to read it. As a first step, we are going to enable rake migrations by appending the following code to the
# simple_api/Rakefile require "rom/sql/rake_task" task :environment do require_relative "config/app" require "hanami/prepare" end namespace :db do task setup: :environment do Hanami.app.prepare(:persistence) ROM::SQL::RakeSupport.env = Hanami.app["persistence.config"] end end
We will add all the necessary code and then we will rebuild the
A migration for table creation
# simple_api/db/migrate/20230228200134_create_books.rb ROM::SQL.migration do change do create_table :books do primary_key :id column :title, :text, null: false column :author, :text, null: false end end end
and a relation
# simple_api/lib/simple_api/persistence/relations/books.rb module SimpleAPI module Persistence module Relations class Books < ROM::Relation[:sql] schema(:books, infer: true) end end end end
Once it’s finished, we can rebuild the image and restart the containers. Then we can connect with a shell on the
app container by calling
docker-compose exec app sh . We have to run migrations by executing
bundle exec rake db:migrate . Then
hanami console and
app["persistence.rom"].relations[:books].insert(title: 'The Alloy of Law', author: 'Brandon Sanderson') . Inserting data itself shows us that the connection is working, but let’s try to read data:
Voila! We have the Hanami application connected with PostgreSQL database. For more, you can visit the Hanami 2.0 getting started guide. I appreciate you reached the end of the article, thank you. Enjoy playing with Hanami.
Goumbik for the background photo