Appwrite

Gliederung

  1. Motivation
  2. Features
  3. Installation
  4. Architektur
  5. Geschäftsprozess
  6. Alternativen
  7. Quellen

Motivation

Die Backendentwicklung für eine im produktiven Umfeld genutzte Anwendung ist eine zeitaufwändige Angelegenheit. Damit die Anwendung sinnvoll genutzt werden kann, ist es meist nötig eine Datenbank zu betreiben, verschiedene Nutzer mit verschiedenen Zugriffsrechten zu verwalten, und eine sinnvolle REST-API bereitzustellen. Dies sind alles Schritte die in den meisten Backends ähnlich gelöst werden müssen. Damit nicht jedes mal von neuem eine Lösung geschaffen werden muss gibt es sogenannte Backends-as-a-Service (BaaS). Diese haben das Ziel die Modellierung, das Hosting und die Integration in die Anwendung deutlich zu vereinfachen. Bereits bekannte und weit verbreitete BaaS sind zum Beispiel Firebase von Google oder Amplify von den Amazon Web Services. Diese sind jedoch proprietär und haben somit die Eigenschaft, dass wenn man einmal sich für einen der beiden Anbieter entscheidet, der Wechsel zu einem Alternativprodukt sich sehr schwer gestalten kann. Als Quelloffene Alternative bietet sich das in diesem Blog-Beitrag behandelte Appwrite. Dies ist ein noch relativ junges Startup welches im Jahr 2021 an den Mark gekommen ist und im Oktober 2022 die Version 1.0 erreicht hat. Bei Appwrite werden ausschließlich Quelloffene Technologien eingesetzt welches das Produkt zum einem selbst-hostbar und zum anderen einfach zum wechseln zu eventuellen alternativen macht. In Appwrite werden die meisten für ein Backend benötigten Features bereitgestellt. Dies geschieht indem verschiedene Docker-Container für einzelne verfügbare Services bereitgestellt werden, welche dann miteinander zusammenarbeiten. So gibt es bei Appwrite eine Datenbank für die Persistierung von Daten, welche gleichzeitig eine REST-API bereitstellt. Um die Business-Logik des Backends darzustellen können einerseits Cloud-Functions oder bereitgestellte Server-SDKs verwendet werden. Für die Client Anwendungen werden ebenfalls SDKs für alle weit verbreiteten Programmiersprachen bereitgestellt.

Features

Datenbank

Im Appwrite können belibig viele Datenbanken angelegt werden. Verwendet wird dabei eine NoSQL-Abstraktion über bereits existierenden Datenbanksystemen. Es sind Treiber für MariaDB (welches auch standardmäßig voreingestellt ist), MySQL und MongoDB vorhanden.

In einer Datenbank können verschiedene Tabellen erstellt werden welche dann Dokumente enthalten. Die einzufügenden Dokumente können mithilfe von Filterkriterien auf Zulässigkeit geprüft werden. Für einen höhere Effizienz der Datenbank können außerdem selbst erstellte Datenbank-Indexe erstellt werden. Relationen werden von der Appwrite-Datenbankabstraktion nicht unterstützt. Sollten diese benötigt werden, müsses diese über selbst erstellte Functions implementiert werden.

Bei der Erstellung von Datenbanken und Tabellen ist der Zugriff auf die Dokumente standardmäßig nur den Administratoren erlaubt. Mithilfe von Security Regeln können Zugriffsregeln entweder Tabellenweit oder für jedes einzelne Dokument konfiguriert werden. Alle Erstellten Tabellen und Dokumente sind für die Zugriffsberechtigten Nutzer sofort mittels einer automatisch Generierten REST- und GraphQLschnittstelle abrufbar.

Authentifizierung

Um den komplizierten und oft auch fehleranfälligen vorgang der Authentifizierung von Nutzern zu vereinfachen bietet Appwrite einen Authentifizierungsservice an. Mithilfe dieses Services können Accounts erstellt und verwaltet werden. Die Accounterstellung ist hierbei zum Beispiel mittels Email und Passwort, diversen OAuth-Anbietern, einer magic-URL oder weiteren Alternativen möglich. Auch Anonyme Benutzer können erstellt werden. Mithilfe von Teams können Benutzer in verschiedene Gruppen mit eigenen Zugriffsberechtigungen eingeteilt werden.

Functions

Mithilfe von Appwrite-Functions kann die Funktionalität von Appwrite erweitert werden. Diese bieten die Möglichkeit auf alle internen Appwrite-Events zu reagieren. Zudem können Functions mittels einer bereitgestellten REST-Schnittstelle aktiviert werden. Auch das zyklische Ausführen von Functions mittels einem in der CRON-Syntax beschriebenen Zeitplanes ist möglich.

Für die Erstellung von Appwrite-Functions stehen SDKs in diversen Programmiersprachen zur Verfügung. Eine Auswahl von unterstützten Programmiersprachen ist: Python, Node.js, PHP, Deno, Dart, Swift, .NET, Kotlin, Java, C++, Rust.

Die Ausführung der Functions wird realisiert indem jede einzelne Function ein eigener von Appwrite gemanagter Dockercontainer ist. Das deployen von Functions geschieht am einfachsten über ein von Appwrite bereitgestelltes Kommandozeilenwerkzeug namens Appwrite-CLI. Es ist jedoch auch über die Appwrite-Console oder manuell über die Appwrite-Server-API möglich. Während des deployments wird der Dockercontainer für die Function gebaut. Nach dem erfolgreichen Bauprozesses einer Function kann diese sofort ausgeführt werden. Wie bei der Datenbank ist es hier ebenfalls eine Konfiguration der Ausführungsberechtigten Accounts möglich.

Storage

Der Appwrite-Storageservice ist für die Verwaltung von Dateien zuständig. Der Hauptanwendungszweck ist dabei die Verarbeitung von Bildern, Videos und anderen Dokumenten.

Der Storageservice ist in verschiedene Bereiche aufgeteilt. Einerseits gibt es einen allgemeinen Speicher und andererseits die Speicherung von Dateien in Buckets.

Die Buckets diesen zur besseren Verwaltung von spezifischen Dateien. Ein weit verbreitetes Szenario ist zum Beispiel das Erstellen eines Buckets für Bilddateien. In dem Bucket kann dann unter anderem die maximal zulässige Auflösung und Dateigröße festgelegt werden. Zudem können automatisch nach dem Hochladen eines Bildes, weitere Versionen dieses Bildes mit verschiedenen konfigurierten Auflösungen automatisch generiert werden. Für eine erhöhte Sicherheit der Daten ist kann zudem bei Bedarf eine Verschlüsselung von Dateien stattfinden. Je nach Konfiguration sind auch automatische Vierenscans auf den Dateien möglich.

Realtime

Auf jedes interne Appwrite Event kann mittels Websocktes über die bereitgestellte Realtime-API von außen in Echtzeit reagiert werden. Am Häufigsten wird dieser Service für das automatische Bereitstellen von Änderungen in der Datenbank verwendet. Die Realtime-Funktionalität ist nur über die Client SDKs von Appwrite möglich. Client SDKs sind für Web (Node.js), Flutter, Android (Kotlin) und Apple (Swift) verfügbar.

Console

Die Appwrite-Console ist eine Weboberfläche zur grafischen Verwaltung von Appwrite. Alle für Appwrite Kritischen Funktion können hier aus überwacht und verändert werden. In der Console können neue Datenabnken angelegt, Benutzer verwaltet werden oder Functions ausgeführt werden.

Als Alternative zur Appwrite Console existiert die Appwrite-CLI. Dies ist ein Kommandozeilenwerkzeug welches die Entwicklung von Anwendungen mit Appwrite erleichtert. Auch hier sind alle Appwrite Funktionen abgedeckt.

Installation

Für eine Installtion von Appwrite ist ein installiertes Docker und Docker-Compose zwingend Notwendig.

docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.2.0

Mithilfe dieses Kommandos wird Appwrite mittels Docker auf dem System bereitgestellt. Die während der Installtion vorgenommenenn Konfigurationen werden in einer docker-compose-Datei festgehalten. Weitere Konfiguration findet über eine automatisch bei der Installation erstellte Umgebungsvariablen-Datei statt.

Architektur

Appwrite benutzt eine Microservice Architektur, die speziell auf gute Skalierbarkeit und geteilte Zuständigkeiten ausgelegt ist. Außerdem werden verschiedene APIs wie REST, WebSocket und bald auch GraphQL unterstützt. Auf diese Weise wird dem Anwender erlaubt auf verschiedenen Wegen mit seinen Ressourcen zu Interagieren und dabei seine bevorzugten Protokolle zu verwenden.

Die Appwrite API wurde so konzipiert, dass sie extrem schnell ist, indem sie In-Memory-Caching nutzt und alle komplexen Aufgaben an Background Worker delegiert. Durch diese Background Worker ist es möglich die Rechenkapazität und -kosten, mithilfe einer Message Queue präzise zu steuern.

Appwrite benutzt eine Reihe weiterer Technologien um seine Funktionen umzusetzen (Redis, InfluxDB, MariaDB, Telegraf, ClamAV/SMTP, Letsencrypt). Die bereits genannte Message Queue sowie der Cache der Datenbank wird mit Redis umgesetzt. Die Datenbank selbt wird in einem anderen Kapitel beschrieben, die dafür angewandten Technologien sind InfluxDB für Zeitreihen und eine Abstraktion über MariaDB für sonstige Daten. Zum Sammeln von Metriken zur Applikation wird Telegraf verwendet. So werden dem Nutzer verschiedenen Informationen über sein Sytem zur Laufzeit zur Verfügung gestellt. Für Mails wird ein SMTP Server genutzt. Abhängig von der Version ist auch ClamAV als Virenschutzprogramm enthalten. Zertifikate können in Appwrite per Letsencrypt erstellt werden.

Geschäftsprozess

Der hier dargestellte Geschäftsprozess zeigt das Verfahren beim hinzufügen einer neuen Funktion. Dabei gilt es zunächst die Funktion zu initialisieren. Dies ist beispielsweise über die Konsole mit dem Befehl appwrite init function, oder über die Benutzeroberfläche möglich. Anschließend wird die Funktion implementiert. Da Appwrite sprachunabhängig ist kann dies mit einer beliebigen Programmiersprache geschehen. Sind diese grundlegenden Schritte erledigt müssen einige Entscheidungen getroffen werden, welche den weiteren Ablauf bestimmen.

Die erste dieser Entscheidungen befasst sich mit dem Bedarf an externen Informationen. Denn wenn dieser Bedarf besteht muss eine Umgebungsvariable angelegt werden, über welche die Funktion auf die Informationen zugreifen kann. Ist dies erledigt, besteht die Möglichkeit weitere Besonderheiten, wie zum Beispiel einen Timeout oder spezielle Zugriffsberechtigungen, festzulegen. Des Weiteren wird bestimmt auf welche Art und Weise die Funktion ausgelöst werden soll. Standardmäßig erfolgt die Auslösung über HTTP-Request, doch es gibt auch die Möglichkeit die Auslösung über Cron-Jobs oder spezielle Events zu definieren. Soll dies geschehen ist die entsprechend ein Cron-Job zu erstellen bzw. das auslösende Event festzulegen.

Damit ist die Funktion fertig konfiguriert und kann nun deployed werden. Dies ist wie oben schon auf verschiedenen Wegen möglich, beispielsweise mit dem Befehl appwrite deploy function in der Konsole. Zu diesem Zeitpunkt ist die Funktion bereit zur Ausführung.

Die Ausführung kann je nach den zuvor getroffenen Einstellungen auf verschiedenen Wegen geschehen. Diese beeinflussen der Ablauf der Funktion allerdings nicht weiter. Anschließend ist die Funktion wieder zur Ausführung bereit. Ab dem Zeitpunkt der Bereitstellung der Funktion kann sich der beschriebene Ablauf beliebig häufig wiederholen.

Alternativen

Firebase

Mit Blick auf die zur Verfügung stehenden Features können Appwrite und Firebase nahezu als gleichwertig angesehen werden. Der Hauptunterschied liegt hier in der Art und Weise in der das Backend zur Verfügung gestellt wird. Während Firebase nur in der Google Cloud Platform verfügbar ist, wird Appwrite selbst gehosted. Dadurch ist die Konfiguration und das Bereitstellen von Appwrite deutlich anspruchsvoller als bei Firebase. Allerdings hat man auf diese Weise umgekehrt auch eine bedeutend höhere Kontrolle über das Backend. Außerdem ist zu bedenken, dass Appwrite, abgesehen von den entstehenden Kosten für das Hosting, kostenlos ist. Bei Firebase ist hingegen eine Gebühr zu entrichten.

Supabase

Supabase ist ebenfalls eine direkte Alternative zu Appwrite und Firebase. Im Hosting wird hier eine Mittelweg gegangen. Das heißt es ist sowohl möglich Supabase über eine Cloud-Lösung zu beziehen, als auch es direkt selbst zu hosten. Jedoch ist hierbei zu bedenken, dass die selbst gehostete Variante weniger robust und einfach zu handhaben ist, als das Äquivalent von Appwrite. Ein weiterer Unterschied ist die Datenbank, denn bei Supabase wird auf eine Postgres DB gesetzt. Bei Appwrite wird hingegen auf einen Ansatz gesetzt, der stark von NoSQL Datenbanken geprägt wird. Dadurch findet mehr Abstraktion statt und die Einbindung in die Rest API ist sehr einfach möglich.

Quellen

https://appwrite.io/docs/
https://medium.com/appwrite-io/announcing-console-2-0-2e0e96891cb0
https://medium.com/@tkarmakar27112000/appwrite-vs-supabase-vs-firebase-48d1dd79bdc2
https://github.com/open-runtimes/open-runtimes
https://dev.to/appwrite/take-your-serverless-functions-to-new-speeds-with-appwrite-013-5868
https://dev.to/appwrite/it-s-here-announcing-appwrite-0-10-and-the-new-appwrite-realtime-api-lbm
https://res.cloudinary.com/practicaldev/image/fetch/s–38oSSm4b–/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj7mmouviy03u0nct7u5.png
https://www.linode.com/docs/guides/getting-started-appwrite/