In diesem Artikel konzentrieren wir uns auf die Konfiguration der Hanami-Webanwendung zusammen mit der PostgreSQL-Datenbank unter Verwendung von Docker Compose.

Kürzlich habe ich begonnen, mich mit dem Hanami-Framework zu beschäftigen, dessen Version 2 vor ein paar Monaten veröffentlicht wurde. Seitdem ich Docker und Docker Compose kennengelernt habe, verwende ich sie immer wieder, weil sie mir helfen, verschiedene Dienste auf meinem Rechner auszuführen, ohne dass ich die erforderlichen Abhängigkeiten installieren muss, usw. Wenn Sie sie noch nicht kennen, empfehle ich Ihnen, sich mit ihnen vertraut zu machen. Ich finde sie sehr praktisch und möchte sie auch für die Einrichtung eines API-Dienstes verwenden, der mit einer relative Datenbank verbunden ist, in meinem Fall wird es PostgreSQL sein. Los geht’s.

Zuallererst müssen wir sicherstellen, dass die Ruby-Version, die wir verwenden, mindestens die Version 3.0.0 hat. Um zu beginnen, müssen wir den hanami gem installieren.

gem install hanami

Sobald das erledigt ist, erstellen wir eine neue Hanami-Anwendung von Grund auf.

hanami new simple_api

Dieser Prozess erstellt eine Reihe von Dateien innerhalb des Verzeichnisses, das auf den Namen der Anwendungen folgt, die wir im vorherigen Befehl angegeben haben. In meinem Fall ist es simple_api. Nun müssen wir ein Dockerfile erstellen, um die Laufzeitumgebung für unsere Anwendung festzulegen.

FROM ruby:3.2.1-alpine

RUN apk add --update build-base ruby-dev

WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

EXPOSE 2300

CMD ["hanami", "server"]

Wir werden ruby:3.2.1-alpine Image verwenden, um ein überladenes Ruby-Image zu vermeiden, aber es ist erforderlich, zwei Bibliotheken zu installieren, damit es funktioniert: build-base und ruby-dev. Wenn Sie mit Rails vertraut sind, kennen Sie vielleicht die Portnummer 3000, die weit verbreitet ist. Im Fall von Hanami-Anwendungen ist der Standardport 2300. Sobald das Dockerfile fertig ist, können wir ein Image bauen:

docker build -t simple-api -f Dockerfile.dev .

Alles sieht gut aus, also können wir in eine Docker-Kompositionsdatei springen.

# 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

Was wir hier spezifiziert haben, ist der db-Dienst, der die PostgreSQL-Datenbank und unseren Webanwendungsserver darstellt - app. Die Benennung der Images ist ziemlich einfach, wie Sie auch bei den Ports feststellen konnten. Wir werden die Standard-Portnummer verwenden. Ausserdem müssen wir die Umgebungsvariable POSTGRES_PASSWORD zur Datei .env hinzufügen:

# simple_api/.env
POSTGRES_PASSWORD=XYZ123QWE

Lassen Sie uns unsere Container starten:

docker-compose up

Grossartig, alles sieht gut aus, aber es gibt noch eine wichtige Sache zu tun: Wir müssen simple-api Webserver mit Postgres verbinden. Zu Beginn fügen wir ein paar Gems zum Gemfile hinzu.

# simple_api/Gemfile
gem "rom", "~> 5.3"
gem "rom-sql", "~> 3.6"
gem "pg"

Als Nächstes müssen wir die Bibliothek postgresql-dev zur Datei Dockerfile.dev hinzufügen, damit sie das pg Gem erfolgreich installieren kann:

RUN apk add --update build-base ruby-dev postgresql-dev

Lassen Sie uns die Container stoppen, das Image neu erstellen und die Container erneut starten. Bevor wir mit der Verbindung der API-Anwendung mit dem Datenbankserver beginnen, können wir eine Datenbank erstellen:

docker-compose exec db psql -U postgres -c "CREATE DATABASE simple_api_development;"

Nun ist es an der Zeit, das Hanami-Framework selbst näher zu betrachten, denn wir müssen einen Persistenzanbieter hinzufügen:

# 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

Dieser target["settings"].database_url verweist auf eine Umgebungsvariable mit DATABASE_URL, also fügen wir sie zur .env Datei hinzu:

# simple_api/.env
DATABASE_URL=postgres://postgres:XYZ123QWE@db:5432/simple_api_development
POSTGRES_PASSWORD=XYZ123QWE

Wir müssen auch die Einstellung database_url zur Klasse Settings hinzufügen:

# simple_api/config/settings.rb
module SimpleAPI
  class Settings < Hanami::Settings
    setting :database_url, constructor: Types::String
  end
end

Nun können wir unser simple-api-Image neu erstellen und Container neu starten.

Testing

Lassen Sie uns beweisen, dass die Verbindung hergestellt ist und wir die DB benutzen können. Wir werden eine Tabelle erstellen, Beispieldaten einfügen und versuchen, sie zu lesen. Als ersten Schritt werden wir Rake-Migrationen aktivieren:

# 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

Eine Migration zur Tabellenerstellung:

# 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

Und eine Beziehung:

# 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

Sobald dies abgeschlossen ist, können wir das Image neu erstellen und die Container neu starten. Dann können wir uns mit einer Shell auf dem app Container verbinden:

docker-compose exec app sh
bundle exec rake db:migrate
hanami console
app["persistence.rom"].relations[:books].insert(title: 'The Alloy of Law', author: 'Brandon Sanderson')
app["persistence.rom"].relations[:books].to_a

Voilà! Wir haben die Hanami-Anwendung mit der PostgreSQL-Datenbank verbunden. Weitere Informationen finden Sie im Hanami 2.0 Getting Started Guide.