Node.js Hosting & Strapi im Backend

Das Hosting von einem Node.js Monitoring-Tool brachte mich darauf, auch mal ein Node.js Backend auszuprobieren. Die Wahl fiel auf Strapi und Nuxt für das Frontend

Node.js Hosting & Strapi im Backend
Photo by Markus Spiske / Unsplash

Schon seit einiger Zeit ist das selbst gehostete Monitoring-Tool Uptime Kuma von Louis Lam bei mir auf GitHub mit einem Stern markiert. Ich wollte es schon immer mal installieren und ausprobieren, hab mir aber nie die Zeit dazu genommen. Ein Grund dafür war, dass ich bisher noch keine Node.js Anwendung gehostet habe und ein Monitoring Tool, das ich selbst überwachen muss, in meinen Augen keinen Sinn machte.

Mit meinem Wechsel zu Docker hatte ich jedoch vollkommen neue Möglichkeiten und hab einfach mal analog zur Anleitung eine docker-compose.yml erstellt:

version: '3'
services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: always
    ports:
      - "3001:3001"
    volumes:
      - uptime-kuma:/app/data

volumes:
  uptime-kuma:

Anschließend ersetzte ich das Docker-Volume durch einen einfachen "data"-Ordner, weil ich gerne sehe, was darin landet und fügte traefik-Labels hinzu. Zusätzlich musste dafür noch das Network hinzugefügt werden, aber den Port konnte ich mir dann sparen:

version: '3'

services:
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    volumes:
      - ./data:/app/data
    restart: always
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.uptime.entrypoints=websecure"
      - "traefik.http.routers.uptime.rule=Host(`uptime-kuma.zebra-fruit.de`)"
      - "traefik.http.routers.uptime.tls.certresolver=http_resolver"
      - "traefik.http.services.uptime.loadbalancer.server.port=3001"
      - "traefik.docker.network=proxy"
networks:
  proxy:
    external: true

Nach einem docker compose up und einer kurzen Wartezeit hatte ich das Vergnügen zu sehen, dass es funktionsfähig und abrufbar war. Hätte ich früher gewusst, dass das so easy geht, wäre das Tool wahrscheinlich schon seit 1-2 Jahren in Betrieb.

Für alle, die noch nicht mit traefik vertraut sind:
Bei der Installation von traefik habe ich mich an den sehr guten Artikel von GoNeuland gehalten - Danke Jonathan 🙏

Ich habe einige persönliche Projekte zu Uptime Kuma hinzugefügt und nach ein paar Tagen geschaut, wie sie laufen. Leider musste ich feststellen, dass mein Laravel Projekt mit einer durchschnittlichen Antwortzeit von circa 400ms das Schlusslicht bildete.

Da ich nun schon erste positive Erfahrungen in Richtung Node.js Hosting gemacht hatte und auch immer etwas blauäugig durch die Welt gehe, musste also das Laravel Backend dran glauben. Für das Frontend habe ich mich für Nuxt.js entschieden, da ich damit bereits gute Erfahrungen gemacht habe. Als Backend kam das Headless CMS Strapi zum Einsatz.

In meinem Projektordner bike-note habe ich Strapi mit folgendem Befehl installiert:

npx create-strapi-app@latest api

(Voraussetzung ist, dass man npm lokal installiert hat)

Im Dialog habe ich mich für den Installationstyp Quickstart entschieden und wenn der Prozess abgeschlossen ist, öffnet sich das Admin-Panel über localhost:1337 im Browser - nett.

Man wird aufgefordert, einen Content-Type zu erstellen, was quasi eine Datenbankmigration ist, und wird zum Content-Type Builder weitergeleitet. Unterschieden wird zwischen den Folgenden:

  • Collection Types: Im klassischen CMS wären das die Posts
  • Single Types: einzelne Seiten, wie z.B. das Impressum
  • Components: Bausteine, die man überall verwenden kann

In meinem Projekt Bike Note, kann jeder User mehrere Motorräder anlegen und für diese jeweils Notizen machen. Das ergab die 3 Collection Types: User, Bike und Note. Die Felder und Typen konfiguriert man im Browser per Drag & Drop und im Hintergrund werden Controller, Route und Service automatisch angelegt.

Der Content Manager ermöglicht das Suchen, Filtern, Bearbeiten und Erstellen von Inhalten, wie man es von Content Management Systemen gewohnt ist. Ich erstellte erstmal einige Beispiele und schaute mir an, wie die API funktionierte. Unter Settings > USERS & PERMISSIONS > Roles sind standardmäßig die Rollen Authenticated und Public zu finden. Für einen schnellen Test habe ich der Public Rolle erlaubt alle Bikes zu finden und localhost:1337/api/bikes aufgerufen: Forbidden. Okay, man darf nicht vergessen, den Save-Button zu klicken. Gespeichert und nochmal aktualisiert: Cool, mein Motorrad tauchte als JSON im Browser auf, also ging es nun mit dem Frontend weiter.

Im Projektordner bike-note also folgende Befehle ausgeführt:

Für die Installation von Nuxt:
npx nuxi@latest init client

Dann in das client Verzeichis wechseln und das Strapi Modul installieren:
npx nuxi@latest module add strapi

Nuxt Strapi ist das offizielle Modul, das glücklicherweise gut dokumentiert ist. Daher will ich in diesem Artikel nicht zu tief in meinen Frontend-Code eintauchen. Hier dennoch ein paar kurze Beispiele der Composables:

  • Über eine Middleware prüfen, ob ein User eingeloggt ist:
const user = useStrapiUser()

if (!user.value && !['/login', '/register'].includes(useRoute().path)) {
  navigateTo('/login');
}
  • Ein einfacher Login:
const { login } = useStrapiAuth()

const form = reactive({ identifier: '', password: '' })

const onSubmit = async () => {
  try {
    await login(form)
  } catch (e) {
    console.error(e)
  }
}
  • Motorräder für die Übersicht laden:
const { find } = useStrapi()

const bikes = ref<Array>([]);

const loadBikes = async () => {
  const { data } = await find('bikes');
  bikes.value = data;
}
  • Eine neue Notiz speichern:
const { create } = useStrapi()

const createNewNote = async () => {
  await create('notes', form);
}

Wenn man Strapi verstanden hat, ist die Anwendung wirklich schnell gebaut. Man darf nur nicht zwischendurch immer wieder vergessen, dass man für jeden neuen Type auch wieder die Permissions setzen muss 😅

Ich glaube, ich habe mehr Zeit damit verbracht, Vue-Komponenten zu stylen, als mich um das Backend zu kümmern, was erfrischend ist, wenn man jahrelang Full Stack mit Laravel gemacht hat. Falls man also kleine Projekte schnell umsetzen möchte, kann ich jedem Empfehlen, die Kombination mal auszuprobieren.

Noch mehr Zeit habe ich aber mit dem Deploy verbracht, worauf ich im nächsten Artikel eingehen werde. Schaltet also auch beim nächsten mal wieder ein 😜