Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 29 Min.

Einbinden von Backends

Im Zentrum der Backends einer Ionic-App stehen neben Performance und Skalierbarkeit vor allem eine Gewährleistung von Datenschutz und Ausfallsicherheit.
© Shutterstock
Im Software-Engineering unterteilt man jede Anwendung ganz grob gesehen in zwei Bestandteile: Front- und Backend (Bild 1). Zum Frontend gehört alles was der Endbenutzer sehen und in visueller Form erleben kann – daher bezeichnet man das Frontend gelegentlich auch als Präsentationsebene. Im Unterschied zum Frontend bezieht sich das Backend auf alles, was dem Benutzer gegenüber nicht sichtbar im Hintergrund abläuft.
Die Architektur jeder Anwendungbesteht aus mindestens zwei Bestandteilen: Front- und Backend(Bild 1) © Simon
Hierzu zählen verschiedene Servertypen (Webserver, Application- oder File/Datenbank-Server) mit denen das Frontend kommuniziert. Aber auch Middleware mit anwendungsneutralen Diensten wie Druck, Datenschutz, -sicherheit, Fehlerhandling oder Logging gehört zum Backend.Innerhalb der Anwendungslandschaft eines Unternehmens existieren häufig verschiedene Backends, die für mehrere Anwendungen parallel ihre Dienstleistungen vorhalten. So greifen zum Beispiel auf einen Datenbank-Server mit den Kundendaten und Umsätzen sowohl der Online-Shop, die Finanzbuchhaltung als auch das Controlling-System zu. Damit stellt dieses Backend eine wichtige Komponente für die genannten Anwendungen dar. Somit gilt das Backend häufig als der kritischste Teil einer jeden Anwendung – für nicht offline-fähige Apps bewirkt die Nichtverfügbarkeit des Backends sogar einen vollständiger Anwendungsausfall.

Der Rest-Parameter und die Spread-Syntax

In JavaScript-Quellcode sieht man gelegentlich drei aufeinanderfolgende Punkte: …, dabei handelt es sich entweder um Rest-Parameter oder die Spread-Syntax. Treten die … innerhalb einer Funktion oder ähnliches auf, so spricht man von der Spread-Syntax. Diese … dienen dazu, die Elemente eines Arrays in eine Liste zu verteilen/aufzunehmen. Kommen die … am Ende von Funktionsparametern vor, so spricht man von Rest-Parametern, diese sammeln die nachfolgende Liste von Argumenten an ein Array und reichen dieses als Parameter an die Funktion weiter.
Über die Homepage von Ionic erhält man Zugang zur Webseite: Integrations - Premier and community integrations to help your apps do more. Dort führt der Hersteller alle gängigen Tools der Open Source-Community und auch speziell von Ionic entwickelte Werkzeuge zur Anbindung von Backend-Services auf. Die Webseite gliedert alle erfassten Systeme in verschiedene Kategorien und sortiert diese in alphabetischer Reihenfolge. Zu den sicherlich wichtigsten Services/Integrations gehören die Kategorien: Analytics, Authentication, …, Databases, DevOps, Messaging, …, Payments, …, Security, Social…. Abhängig vom konkreten System überlappen sich unter Umständen die jeweiligen Kategorien.

Doppelstrategie von Ionic zur Integration von Backend-Services

Zudem unterteilt Ionic die genannten Systeme grundsätzlich in zwei Gruppen: Premier und Community. Klickt man auf die Checkbox Premier, so zeigt die Webseite alle Services an, die Ionic als sogenannte Paid integration with official Ionic support über einen Software-Vertrag mit weitreichender Unterstützung anbietet. Dieser umfasst neben den Ionic-Produkten auch Produkte von Drittherstellern.Wählt man die Checkbox Community an, so erscheinen auf der Webseite alle Systeme für die eine sogenannte Free, community-supported integration zur Verfügung steht. Für diese Services erhält man im Rahmen einer Open-Source-Initiative über das Internet eine Unterstützung seitens der Open-Source-Gemeinde. Die Premier-Services gehören als Bestandteil zu den Enterprise-ready tools and services im Rahmen von Ionic for Enterprise. Dabei handelt es sich zum einen um konkrete Services/Produkte, zum anderen auch um eine ganz individuelle Unterstützung. Hierzu vereinbart ein Unternehmen zusammen mit Ionic einen sogenannten Custom Plan, der für ein Projekt oder App die erforderliche Hilfestellung festlegt. Der Custom Plan umfasst die gewünschten Produkte und einen individuell noch zu spezifizierenden Umfang an zusätzlichem Support. Als Ausgangsbasis für die individuelle Integration von Backends hat Ionic eigene auf das Framework abgestimmte Services entwickelt:Prinzipiell besteht eine Ionic-App, die mit einem oder mehreren Backends kommuniziert aus zwei Bestandteilen: Auf dem Frontend läuft der dem Endbenutzer gegenüber sichtbare Client-Teil, während das Backend den Server-Teil der App ausführt. Die Struktur eines Projektordners gliedert sich demnach in mindestens zwei Hauptverzeichnisse: backend und frontend, die sich jeweils gezielt mit diesen beiden separaten Aufgabenbereichen der Programmierung befassen. Nimmt die Ionic-App Leistungen, das heißt Services von mehreren Backends in Anspruch, so bietet es sich an, für jedes Backend ein eigenes Unterverzeichnis im backend-Projektordner anzulegen.
Die Einbindung von Backend-Serviceserfolgt über ein vom Quellcode der eigentlichen Ionic-App getrenntes backend-Verzeichnis(Bild 2) © Simon
Ausgehend vom Hauptverzeichnis eines Ionic-Projekts untergliedert sich dieses in die beiden Unterordner backend und frontend (Bild 2). Der Ordner frontend enthält alle Bestandteile, die sich mit der Programmierung der eigentlichen Ionic-App befassen. Dort befindet sich der komplette Quellcode mit den Entwicklungs-, Test- und Konfigurationsdateien für die Client-Seite. Damit stellt der frontend-Ordner quasi den kompletten Client-Teil der gesamten Anwendung dar. Der Ordner backend befasst sich durchgängig mit der Entwicklung des Server-Teils der Anwendung.

Entwicklungs-, Test- und Konfigurationsdateien

Das backend-Unterverzeichnis des Entwicklungsprojekts enthält die Entwicklungs-, Test- und Konfigurationsdateien für alle eingesetzten Server-Systeme. Für die Einbindung von Spezialisten der Backend-Services eignet sich eine Untergliederung des backend-Ordners nach deren Aufgabengebiete: datenbase, printing, logging und entsprechend weitere. Eine derartig strukturierte Organisation des Entwicklungsprojekts erleichtert wesentlich das Konfigurations- und Change-Management. Zudem unterstützt diese Untergliederung des Projekts nach Client- und einem oder eventuell mehreren Server-Teilen eine aufgabenorientierte Arbeitsteilung zwischen den verschiedenen Entwicklergruppen: Frontend- und Backend-Programmierern.Die Trennung des Hauptordners in entsprechende Entwicklergruppen orientiert sich am benötigten Anforderungsprofil eines Programmierers. Oder anders ausgedrückt – die Aufteilung im Backend erfolgt nach den eingesetzten Technologien, der ihnen zugeordneten Aufgaben und dem spezifischen Knowhow eines Entwicklers. In der Praxis findet man auf dem Arbeitsmarkt bei durchgängigem Einsatz von JavaScript/TypeScript mit den entsprechenden Technologien auch sogenannte Fullstack-Entwickler. In diesem Idealfall deckt der Fullstack-Entwickler die Aufgaben des kompletten Entwicklungsstrangs der Ionic-App ab.

Express – ein Backend für populäre JavaScript-Development-Stacks

Express gilt als Standard-Server-Framework für den Einsatz von Node.js im Backend. Dabei erweitert Express Node.js um spezielle Werkzeuge und stellt diese über Plugins für die Entwicklung bereit. Inzwischen gehört Express neben MongoDB als Datenbank zu den essentiellen Bestandteilen gängiger Development-Stacks: MEAN, MERN und MEVN. In diesen Development-Stacks kommt durchgängig JavaScript sowohl server- als auch client-seitig zum Einsatz. Die Einzelbuchstaben in diesen Akronymen stehen für die jeweils eingesetzte Open-Source-Software: M für MongoDB, E für Express, A für Angular, R für React, V für Vue.js und N für Node.Dabei dient MongoDB als Dokumenten-Datenbank für die Datenhaltung, Express für die Programmierung des Backends auf Basis von Node.js, Angular, React, Vue.js als Werkzeuge für die Entwicklung des Frontends auf dem Client und Node.js als JavaScript-Laufzeitumgebung auf dem Backend. Die Funktionen von Express dienen als Vermittler zwischen einer unformatierten Anforderung und der endgültigen beabsichtigen Weiterleitung. Sie realisieren einen Anforderungs/Antwort-Zyklus: Als minimalistische Middleware führt Express Code aus, nimmt Änderungen an der Anforderung und an Antwortobjekten vor, beendet den Zyklus und ruft gegebenenfalls die nächste Middleware-Funktion auf.

Quellcode-Änderungen automatisch ausführen

Das npm-Package nodemon bietet eine Hot Reload-Funktion für Änderungen einer Node.js-App an. Änderungen im Quellcode einer App auf Basis von Node.js übernimmt nodemon automatisch während der Laufzeit in die App und führt diese aus. Bei nodemon handelt es sich um ein Programm mit CLI (Command Line Interface), das anhand seiner Konfigurationsdatei nodemon.js das Dateisystem auf Änderungen überwacht und die App automatisch mit Node.js neu startet. Für den Einsatz von nodemon reicht eine lokale Installation von nodemon im Projekt, eine globale Installation ist nicht notwendig.
Express instanziiert durch den Aufruf von express() ein zentrales app-Objekt, das mehrere Leistungen zur Verfügung stellt. Dabei führt das app-Objekt ein Routing für HTTP-Requests durch, nimmt eine Konfiguration der Middleware vor, rendert HTML-Views oder registriert eine Template-Engine. Das req(uest)-Objekt repräsentiert HTTP-Requests mit Eigenschaften zum Query-String, Parametern, Body, den HTTP-Headern und dergleichen.Die verfügbaren Methoden nehmen Prüfungen vor oder bestimmen beispielsweise Eigenschaften eines Requests. Beim res(ponse)-Objekt handelt es sich um den HTTP-Response mit seinen Eigenschaften und Methoden zu deren Bearbeitung. Das Router-Objekt führt das Routing durch und bestimmt wie die Antwort auf eine Client-Anforderung an einem Endpunkt aussieht.Die Entwicklung von Ionic-Apps erfolgt in der Regel mit TypeScript; während die Programmierung von Express in Reinform primär auf JavaScript ausgerichtet ist. Das nachfolgende Beispiel zeigt wie man mit TypeScript ein Backend auf der Basis von Express realisiert.Nach Anlage eines Unterverzeichnis backend im Projektordner, erzeugt der Befehl npm init --yes eine initiale package.json-Datei. Die Schlüsseleinträge description, keywords und author bestückt man noch mit passenden Vorgaben des Projekts. Zusätzlich erhält der Schlüssel main in der package.json-Datei den Eintrag express.js, also den Namen der nachfolgenden Quellcode-Datei.

Einrichten eines Express-Backends für Ionic-Entwicklung mit TypeScript

Anschließend führt der Befehl npm install express eine normale Express-Installation im backend-Ordner durch. Die Installation von Express testet ein kleiner Server, der auf localhost über den Port 4711 im Webbrowser die Meldung Express-Server wird ausgeführt! ausgibt. Zusätzlich soll in der JavaScript-Konsole noch die Meldung Express-Server läuft auf http://localhost:4711 erscheinen. Der zugehörige Quellcode befindet sich im Unterverzeichnis express des backend-Ordners in der Datei express.js des Projekts – diese führt der Terminal-Befehl node ./express/express.js aus.

const express = require('express');
const app = express();
const PORT = 4711;
app.get('/', (req,res) => res.send('Express-Server wird ausgeführt'));
app.listen(PORT, () => {
  console.log('Express-Server läuft auf 
  http://localhost:${PORT}');
});
 
 
Die Programmierung von Express mit TypeScript ermöglichen die beiden npm-Bibliotheken typescript und ts-node. Dabei handelt es sich bei typescript um den Compiler, der TypeScript-Quellcode in gültiges JavaScript überführt. Die zweite Bibliothek ts-node stellt eine Utility bereit, um innerhalb einer Entwicklungsumgebung TypeScript-Quellcode direkt von einer Eingabeaufforderung/Terminal-Fenster auszuführen. Der Befehl npm install typescript ts-node --save-dev im server-Verzeichnis installiert die Bibliotheken im backend-Ordner und trägt beide im devDependencies-Bereich der package.json ein. Die neu angelegte Datei tsconfig.json im server-Ordner enthält die Vorgaben für den TypeScript-Compiler:

{ 
  "compilerOptions": {
      "target": "es6",
      "module": "commonjs",
      "rootDir": "./",
      "outDir": "./build",
      "esModuleInterop": true,
      "strict": true
    },
  "include": ["**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}
 
 
Alternativ generiert der Befehl tsc --init eine tsconfig.json-Datei mit Vorgaben, die man passend um include und exclude erweitert und anpasst. Um Express und Node der Entwicklung mit TypeScript zugänglich zu machen, benötigt man deren Typ-Deklarationen. Diese stellt das GitHub-Repository DefinitelyTyped zur Verfügung.Derartige Deklarationsdateien findet man dort für alle Bibliotheken, die ursprünglich in JavaScript und nicht in TypeScript geschrieben wurden. Die zugehörigen npm-Packages beginnen mit dem @types-Namespace. Für Node und Express lauten die npm-Packages also entsprechend: @types/node und @types/express.Die Installation nimmt der Befehl npm install @types/node @types/express --save-dev vor und trägt die zugehörigen Packages im devDependencies-Bereich der package.json ein. Um den JavaScript-Quellcode für TypeScript in der Datei express.ts umzuschreiben, muss man lediglich in der ersten Zeile die require-Anweisung durch einen import-Befehl ersetzen: import express from ‚express‘. Die packages.json-Datei ergänzt man im scripts-Bereich um den Befehl "start": "ts-node ./express/express.ts".Abschließend führt der Befehl npm start den TypeScript-Quellcode aus. Ruft man Node mit dem Loader-Hook esm auf (node --loader ts-node/esm ./my-script.ts), so wird der vom TypeScript-Compiler erzeugte JavaScript-Quellcode nicht mit CommonJS sondern mit ESM (ES Modulen) ausgeführt.

MongoDB-Server für die Datenhaltung im Backend nutzen

Bei MongoDB vom gleichnamigen Hersteller handelt es sich um ein NoSQL-DBMS (Datenbank-Management-System) (Bild 3), das Objekte als Sammlungen JSON-ähnlicher Dokumente verwaltet. Das DBMS ist in C++, JavaScript und Python programmiert, läuft auf Windows, Linux/FreeBSD, macOS, Unix-Derivaten und bietet Schnittstellen für alle wichtigen Programmiersprachen. Die Datenbank unterstützt Load Balancing und Daten-Replikation, dafür kommt als Basis GridFS zum Einsatz. Das virtuelle Dateisystem GridFS (Grid File System) erlaubt es, den Objekten von MongoDB die Größenbeschränkung von 16 MByte zu überschreiten. Von MongoDB existieren drei verschiedene Editions: Community Server, Enterprise Server und Atlas.
Die Abbildung zeigt vier gängige Modellevon NoSQL-Datenbanken – MongoDB gehört zur Klasse Document Store: Daten und Metadaten werden hierarchisch in JSON-basierten Dokumenten gespeichert(Bild 3) © Simon
Als Datenbank-Server für das Backend eignen sich der kostenlose Community Server oder ein kostenpflichtiges Abonnement des Enterprise Servers. Zwischen beiden Produkten gibt es bezüglich der Basisfunktionalität keinerlei Restriktionen. Der Enterprise Server bietet zusätzliche Features, was Authentifizierung/Autorisierung, Auditing, Backup, Integration, Monitoring, Sicherheit und Support betrifft. Bei der Atlas-Edition handelt es sich um einen Cloud-Database-Service, den der Hersteller für seine Cloud-Datenbank MongoDB Cloud Entwicklern zur Verfügung stellt. Für die Programmierung mit JavaScript von MongoDB steht eine Node.js-Library zur Verfügung, die als asynchrones API auch Promises und Callbacks unterstützt.Für die Entwicklung von Anwendungen empfiehlt sich der Einsatz von Mongoose – einer Object Document Mapping (ODM)-Library für Node.js und MongoDB. Mongoose abstrahiert völlig von der Datenbank, innerhalb des Quellcodes arbeitet der Programmierer nur mit den Objekten der Anwendung und ihrer Methoden.Dazu bietet Mongoose für die Dokumente der Anwendung gängige Funktionen der Datenhaltung wie find, insert, remove, save und update an. Zusätzlich stellt der Programmierer weitere fachliche Funktionen als Business Logic (Geschäftslogik) bereit. ODM erlaubt auch die Spezifikation von Beziehungen zwischen den verschiedenen Objekttypen über ein Objektmodell.

Online/Fake-REST APIs zur Datenbereitstellung

Verschiedene Online/Fake-Rest APIs im Web unterstützen Entwickler beim Prototyping von REST-Schnittstellen durch eine schnelle Bereitstellung von Daten. Jedes dieser Online/Fake-Rest APIs bietet individuelle Daten mit unterschiedlichen Zusatzfunktionen an. Zu den bekanntesten zählen: api-now, JSONPlaceholder, fakeJSON, Fake Store API, mocky, MockServer, Reqres und WireMock. Mit dem npm-Package json-server baut man schnell selbst eine eigene lokale REST-Schnittstelle mit individuellen Daten.
Grundsätzlich benötigt man für die Programmierung eines MongoDB-Servers mit Mongoose eine Installation von Node.js und des DBMS; zudem muss der MongoDB-Service als Background-Prozess (mongod) gestartet sein. Der Befehl npm install mongoose --save im backend-Ordner des Ionic-Entwicklungsprojekts installiert die Mongoose-Library und trägt diese im dependencies-Bereich der package.json-Datei ein. Zur Ablage der Quellcode-Dateien für die Mongoose-Entwicklung dient entsprechend der Ablagestruktur im backend-Ordner ein neu anzulegendes Verzeichnis mongoose. Dort erzeugt man eine Datei default.ts mit den Spezifikationen für den Zugriff auf eine Datenbank:

export default {
    port: 4711,
    host: "localhost",
    dbUri: "mongodb://
    localhost:27017/angestDB"
  }
 
 
Diese Spezifikationen stellen über den genannten Port 4711, den Host localhost und der URI mongodb://localhost:27017/angestDB die MongoDB-Datenbank angestDB für Zugriffe bereit. Zusätzlich könnte man in dieser Datei noch einen Schlüssel db mit Einträgen für verschiedene Datenbanken Produktion, Entwicklung und Test einrichten. Die obigen Angaben darf man nicht mit den Konfigurationseinstellungen wie Authorisierung, Indizierung, Logging, Replizierung, Sharing, Speicherzuordnung, Verschlüsselung oder Zugriffsmodi eines MongoDB-Servers verwechseln. Diese definiert der Datenbank-Administrator in einer separaten mongod.conf-Datei.

MongoDB-Server für Programmierung mit Mongoose einrichten

Der Befehl mongod --config /usr/local/etc/mongod.conf --fork startet über einen Hintergrundprozess einen MongoDB-Server und macht die in der mongod.conf genannte Datenbank für Zugriffe seitens der Anwendungen zugänglich. Das Lesen und Bereitstellen der Spezifikationen aus der default.ts-Datei erledigt eine asynchrone Funktion connect() über das config-Modul. Diese baut über Mongoose die Verbindung zur MongoDB-Datenbank mit der connect-Methode auf, die ein Promise zurückliefert. Der dortige try-catch-Block stellt über die await-Anweisung den Zugriff auf die Datenbank und ein eventuelles Fehlerhandling sicher:

import mongoose from "mongoose";
import config from "config";
// Eventuell noch Logger fuer Protokollierung einrichten
// import log from "./logger";
async function connect() {
  const dbUri = config.get("dbUri") as string;
  try {
    await mongoose
      .connect(dbUri, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true
      });
    console.log("Database connected");
  } catch (error) {
    console.log("Datenbank-Fehler", error);
    process.exit(1);
  }
}
 
export default connect;
 
 
Die Ausführung der connect()-Methode erfolgt asynchron, so dass die Anwendung parallel weitere Aktivitäten starten kann. Solange man während der Entwicklung keine Protokollierung über einen Logging-Service einsetzt, übernimmt diese die console.log-Methode. Zum Einsatz kommt die Middleware express.json und express.urlencoded. Den über Express implementierten Webserver startet man mit dem aus der default.ts-Datei eingelesenen Host und der dort angegebenen Port-Adresse. Dazu nutzt man die listen()-Methode der Express-Instanz app; diese ruft auch die connect()-Methode auf und instanziiert die Routes für die Express-Instanz app:

// backend/src/app.ts
import express from "express";
import config from "config";
// import log from "./logger/logger";
import connect from "./db/connect";
import routes from "./routes";
const port = config.get("port") as number;
const host = config.get("host") as string;
const app = express();
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// Jeden req auf Console ausgeben
app.use((req, res, next) => {
  console.log("request.body: " + req.body)
    next();
 });
app.listen(port, host, () => {
  console.log(`Express-Server läuft auf 
  http://${host}:${port}`);
  //Verbindung zum Datenbank-Server aufbauen
  connect();
  routes(app)
});
 
 
In der Datei routes.ts befinden sich die Definitionen für die Aufrufe der get- und post-Methode mit den Pfadangaben und Request/Response-Funktionen beziehungsweise der Handler-Funktion createAngestHandler. Entsprechend den URL-Konventionen kann man über den Pfad auch Parameter seitens der Ionic-App an das Backend durchreichen. Die Ionic-App nutzt dazu die beim Routing definierten get- und post-Methoden und führt die Zugriffe über einen HTTP(S)-Clients durch. Der Express-Server bringt auf dem Backend die zugeordneten Response- oder Handler-Funktion zur Ausführung und übergibt deren Ergebnis an die Ionic-App:

// backend/src/routes.ts
import { Express, Request, Response } from "express";
import { createAngestHandler } from 
"./controller/angest.controller";
export default function (app: Express) {
    app.get("/healthcheck", (req: Request, res: 
    Response) => res.sendStatus(200));
    // Daten in die Datenbank einfügen
    app.post("/insertdata", createAngestHandler);
}
 
 
Die Handler-Funktion createAngestHandler stellt die Datei angest.controller.ts bereit. Sie legt man im backend-Projektordner im Unterverzeichnis controller ab. Für jede Handler-Funktion benötigt man eine derartige Datei – sie definiert eine gleichnamige asynchrone Funktion und führt über eine weitere Funktion (hier: createAngest) die Datenbank-Zugriffe aus. Danach erfolgt über die obige app.use()-Methode eine Protokollierung des body-Requests in der Console:

// backend/src/controller/angest.controller.ts
import { Request, Response } from "express";
import { createAngest } from 
"../service/angest.service";
export async function createAngestHandler(req: Request, res: Response) {
    const body = req.body;
    const post = await createAngest({ ...body });
    return res.send(post);
}
 
 
Die Durchführung der Zugriffe auf eine MongoDB-Datenbank erfolgt in Mongoose über ein Datenbank-Schema. Dabei handelt es sich um die Definition des Aufbaus eines MongoDB-Dokuments; es legt dessen Felder mit den zugehörigen Datentypen und ihren Integritätsbedingungen fest. Die Verbindung von Datenbank und Schema übernimmt eine Model-Instanz. Im Beispiel einer Angestellten-Datenbank besitzt jedes eingetragene Dokument einen Namen als Pflichtfeld (required: true), der aus einer Zeichenkette besteht. Zusätzlich bekommt jeder Angestellte eine Nummer zugeordnet, die eindeutig (unique: true) sein soll. Die Deklaration der Angestellten-Dokumente übernimmt das angestSchema. Die Instanziierung des zugehörigen Modells erfolgt über die model()-Methode:

// backend/models/angest.model.ts
import { Document, Model, Schema, 
model } from "mongoose";
export interface AngestDocument 
extends Document {
  name: string;
  nummer: number
}
const angestSchema: Schema = new Schema(
  {
    name: { type: String, required: 
    true},
    nummer: { type: Number, required: 
    true, unique: true } 
 });
// Eine Collection angests in der 
// MongoDB-Datenbank erzeugen
const Angest: Model<AngestDocument> = model("Angest", angestSchema);
// Achtung: Mongoose erzeugt immer
// Namen der Collections in Plural 
// und kleingeschrieben: aus 
// Angest wird angests!
export default Angest;
 
 
Die eigentlichen Zugriffe auf die Dokumente eines Angestellten führt eine angest.service.ts-Datei durch, die der Entwickler im Unterverzeichnis service des backend-Ordners ablegt. Eine derartige Datei legt man für jeden Dokumenttyp der MongoDB-Datenbank an. In einer service.ts-Datei programmiert der Entwickler sämtliche Zugriffe auf den zugehörigen Dokumenttyp (hier: Angest). Jeder Zugriff erledigt eine spezielle asynchrone Funktion (hier: createAngest), diese greift dazu auf die jeweilige Mongoose-Methode (hier: create) zurück. Der try-catch-Block stellt sicher, dass ein in input übergebenes Angestellten-Dokument in der MongoDB-Datenbank erzeugt und gespeichert wird:

// backend/src/service/angest.service.ts
import { DocumentDefinition } from "mongoose";
  import Angest, { AngestDocument } 
  from "../models/angest.model";
  export async function createAngest(input: 
  DocumentDefinition<AngestDocument>) {
    try {
        return await Angest.create(input);
      } catch (error) {
        throw new Error(error);
      }
  }
 
 
Während MongoDB Community Server kostenlos zur Verfügung steht, stellt MongoDB Enterprise Server ein lizenzpflichtiges Produkt dar. MongoDB Atlas bietet DBMS-Features, die der Hersteller über die Cloud-Plattformen AWS, Microsoft Azure und Google Cloud bereitstellt. Daher bezeichnet man manchmal MonogDB Atlas auch als Cloud-Datenbank. Von MongoDB Atlas gibt es drei verschiedene Pläne: Shared, Dedicated und Multi-Region. Für die Entwicklung kleiner Apps eignet sich der kostenlose Plan Shared. Die beiden anderen Pläne unterscheiden sich in ihren verschiedenen Ausprägungen von Skalierung, Replikation und Verfügbarkeit.

MongoDB Realm bietet Offline-Datenhaltung mit Backend-Sync

Für die Entwicklung offline-fähiger Apps empfiehlt MongoDB den Einsatz von MongoDB Realm – einer Menge von integrierten Application Development Services. Das Produkt stellt den Offline-First Environment-Ansatz in den Vordergrund. Programmierer entwickeln mit MongoDB Realm eine offline-fähige App, deren Datenhaltung primär lokal erfolgt. Diese lokale Datenbank nennt sich Realm Mobile Database – das Produkt Realm hat MongoDB 2019 übernommen. Es gilt als benutzerfreundlicher als CoreData oder SQLite. Im Bedarfsfall kann man die Daten von Realm Mobile Database mit MongoDB synchronisieren – diese Aufgabe übernimmt automatisch der Service MongoDB Realm Sync.Um MongoDB Realm zu nutzen, benötigt man einen Account beim Hersteller. Nach dem Einrichten des Accounts wählt man einen von drei sogenannter Paths aus: Shared Clusters, Dedicated Clusters und Dedicated Multi-Cloud & Multi-Region Clusters. Diese drei Paths orientieren sich an den drei zuvor beschriebenen Plänen von MongoDB Atlas. Anschließend bietet die Webseite verschiedene Auswahloptionen (Bild 4) an, um die für den konkreten Anwendungsfall notwendige nächsten Schritte auszuführen. So kann man über Cloud eine MongoDB Atlas-DB einrichten, über On-premises, Tools oder Mobile & Edge die benötigte Software herunterladen oder über einen Link die zugehörige Dokumentation erkunden.
Der Account von MongoDB Realmmacht alle dazu gehörenden Services mit Software und Dokumentation direkt zugänglich(Bild 4) © Simon
Nach der Anlage eines MongoDB Atlas-Accounts bietet die Website die Vergabe eines Projektnamens und die Auswahl der bevorzugten Programmiersprache an. Der ausgewählte Projektname AngestDBCloudEntwick verdeutlicht, dass es sich um die Angestellten-Datenbank in der Cloud für die Umgebung Entwicklung (development) handelt. Für Test (test) und Produktion (production) verwendet man eigenständige, isolierte Projekte. Die Festlegung der bevorzugten Programmiersprache zeigt die seitens MongoDB vorhandenen Code-Beispiele passend für diese Sprache an.

Datenbank der Backend-Entwicklung zugänglich machen

Nach Anlage eines Path/Clusters, Auswahl des Cloud Providers und der Region definiert man über die linken Menübereich SECURITY > Database Access die gewünschten Datenbank-Benutzer. Über den Eingabebereich Password Authentication trägt man im ersten Eingabefeld einen Benutzernamen und vergibt im zweiten ein Kennwort.Es dauert einen kurzen Zeitraum bis die MongoDB Atlas-Datenbank in der Cloud dem Entwickler zur Verfügung steht. Nach Auswahl des linken Menübereich DATA STORAGE > Clusters erscheint rechts der neu eingerichtete Cluster0. Klickt man dort auf die Schaltfläche CONNECT, so vergibt man die Zugriffsrechte seitens der Client-Apps.
MongoDB bietet drei Zugriffsoptionenfür seinen Cloud-Datenbank-Service(Bild 5) © Simon
Sollen die Zugriffsrechte unabhängig von einer IP-Adresse sein, so wählt man die Schaltfläche Allow Access from Anywhere aus. Ein Klick auf Choose a connection method zeigt alle drei verfügbaren Zugriffsmöglichkeiten für die MongoDB Atlas-Datenbank an (Bild 5). Wählt man einen der drei angezeigten Zugriffsoptionen aus, so erscheinen weitere Information, die der jeweilige Benutzer für den Zugriff benötigt. Diese umfassen insbesondere den Connection-String, den man für den eigentlichen Zugriff seitens der App oder eines der beiden MongoDB-Tools (mongo shell oder MongoDB Compass) benötigt.

Zugriffe auf MongoDB Cloud über MongoDB Atlas durchführen

Im Connection-String ändert man Kennwort (password) und Datenbank-Namen entsprechend des gewünschten Benutzers und der definierten Datenbank ab. Bisher existiert in der Cloud noch keine Datenbank, diese definiert man im linken Auswahlbereich DATA STORAGE > Clusters durch Klick auf die Schaltfläche COLLECTIONS. Die Schaltfläche Add my Own Data öffnet das Dialogfenster Create Database. Dort vergibt man einen Namen für Datenbank und die erste Collection (Ansammlung von Dokumenten). Die Namen unterscheiden Groß- und Kleinschreibung, gewisse Sonderzeichen ausgeschlossen und Beschränkungen, was die Länge der Namen betrifft, sind einzuhalten.Die Festlegung der beiden Namen orientiert sich am bisherigen Quellcode: Der Name der Datenbank lautet angestDB und der Collection: Angest. Den individuellen Connection-String passt man entsprechend diesen Vorgaben an. Zum Schluss definiert man über den Menübereich SECURITY > Network Access durch Klick auf Add IP Address, ALLOW ACCESS FROM ANYWHERE und Confirm noch den Zugriff über das Netzwerk. Erst dieser Eintrag ermöglicht letztendlich einen Zugriff anhand des Connection-Strings über einen der drei Zugriffsoptionen (mongo shell, Ionic-App oder MongoDB Compass). Dementsprechend übernimmt man den Connection-String für die Zugriffe der Beispiel-App als dbUri in die Datei default.ts:

export default {
    port: 4711,
    host: "localhost",
    dbUri: "mongodb+srv://Manfred:webmobile10@cluster0.
    zpcsn.mongodb.net/angestDB?retryWrites=true&
    w=majority"
  }
 
 
Nach Installation von MongoDB Compass, einer GUI-Anwendung für Abfrage und Manipulation von Daten einer MongoDB-Datenbank, greift der passende Connection-Strings auf die Cloud-Datenbank MongoDB Cloud zu. Dazu startet man diese GUI-Anwendung MongoDB Compass und übernimmt im Bereich New Connection den zuvor ermittelnden Connection-String. Ein Klick auf die Connect-Schaltfläche baut die Verbindung zu Cloud-Datenbank MongoDB Cloud über MongoDB Atlas auf. Anschießend ermöglicht die GUI-Oberfläche von MongoDB Compass eine Abfrage oder Manipulation der in der Cloud-Datenbank vorhandenen Datenbestände.Für VSCodium (siehe Teil 7) findet man im Open VSX Registry die Extension REST Client; für VS Code ist diese im Marketplace ebenfalls vorhanden. Nach Installation dieser Erweiterung steht REST Client in VSCodium (VS Code) zu Verfügung. Der REST Client eignet sich hervorragend zum Testen von HTTP-Requests direkt in der Entwicklungsumgebung. Dazu bietet der REST Client für HTTP eine Sprachunterstützung mit Syntax-Highlighting und automatischer Vervollständigung; vorausgesetzt die Quellcode-Dateien besitzen .http- oder .rest als File-Erweiterung. Alle Dateien mit HTTP-Requests speichert man über den Ordner tests des backend-Hauptordners im http-Verzeichnisses ab:

// POST-Requests zum Einfuegen von Saetzen in 
// die Datenbank
POST http://localhost:4711/insertdata HTTP/1.1
content-type: application/json
{
  "name": "Otto Bauer", 
  "nummer": "11773445" 
}
POST http://localhost:4711/insertdata HTTP/1.1
content-type: application/json
{
  "name": "Udo Heikenwälder", 
  "nummer": "475533282" 
}
…
 
 
Öffnet man in der Entwicklungsumgebung eine .http-Datei, so zeigt der Quellcode-Editor die definierten HTTP-Requests an. Kommentarzeilen beginnen mit einem #- oder zwei //-Zeichen. Vor dem Beginn eines Request-Bodys muss sich beim HTTP-Request immer eine Leerzeile befinden. Ansonsten erhält man eine Fehlerquelle, da der REST Client den Request-Body dann nicht erkennt.Um einen HTTP-Request zu testen, markiert man diesen vollständig im Quellcode-Editor. Öffnet man anschließend das Kontextmenü, so erscheint der Eintrag Send Request. Nach Auswahl dieses Menüeintrags bringt der REST Client den HTTP-Request zur Ausführung.Die Ausführung eines HTTP-Requests über den REST Client setzt voraus, dass vorher der Backend-Server über die Entwicklungsumgebung gestartet wurde. Im Fallbeispiel erledigt dies der Aufruf npm run dev, da die package.json-Datei im Scripts-Bereich den Eintrag "dev": "nodemon --config nodemon.json src/app.ts" enthält.Zusätzlich muss die Adresse des Backend-Servers mit den Adress-Angaben der HTTP-Request übereinstimmen; natürlich muss auch der Port identisch sein. Nach dem Aufruf des Menüs Send Request öffnet der REST Client neben der bereits geöffneten .http-Datei mit den HTTP-Requests einen weiteren Fensterausschnitt.In diesem neuen Fensterausschnitt erscheint der vom HTTP-Server gesendete Response (Bild 6). Denselben Response erhält die Client-Seite im Frontend als Rückantwort, um ihn entsprechend zu verarbeiten. Das komplette Ergebnis speichert ein Klick auf das rechts oben im Fensterausschnitt erscheinende Disketten-Icon ab. Benötigt man nur den Response-Body, so reicht ein Klick auf das Icon der zwei nebeneinanderstehenden Disketten-Symbole aus.
Der REST Client zeigtdas Ergebnis der Ausführung eines HTTP-Requests in einem eigenen Fensterausschnitt an(Bild 6) © Simon
Um den Response-Body in die Zwischenablage zu kopieren, klickt man auf das Icon mit den beiden nebeneinanderstehenden Papierseiten-Symbole. Hat der REST Client einen HTTP-Request ausgeführt, der mit Aktionen in der Datenbank verbunden ist, so lässt sich das Ergebnis unmittelbar über die Datenbank verifizieren.

HTTP-Requests am Frontend für die Ionic-App programmieren

Für die Realisierung von HTTP-Requests am Frontend im Ionic-Client gibt es verschiedene Alternativen:XHR, Fetch-API und Axios stehen für Ionic/Angular, Ionic/React und Ionic/Vue zur Verfügung – während HttpClient nur für Ionic/Angular genutzt werden kann. Die Implementierung von HttpClient befindet sich im Angular-Modul HttpClientModule. Dieses muss in die app.module.ts-Datei nach dem BrowserModule importiert werden. Danach lässt sich der HttpClient-Service über Dependency-Injection (siehe Teil 3) überall nutzen, wo er benötigt wird. HttpClient-Service baut dabei auf XMLHttpRequests auf. Die verschiedenen Services des HttpClients besitzen ähnliche Namen wie die gängigen HTTP-Methoden: get, post, put, delete, patch, head oder jsonp.Die Programmierung mit XMLHttpRequest gestaltet sich komplizierter als mit dem Fetch-API. Bei XHR müssen mehrere Callbacks definiert, Eigenschaften gesetzt und mehrere Methoden in einer bestimmten Reihenfolge aufgerufen werden. Insofern sollte man XHR nicht verwenden, sondern lieber das einfachere Fetch-API einsetzen.Zumal das Fetch-API auch für Service-Worker (siehe Teil 5) zur Verfügung steht. Das Fetch-API basiert auf Promises, die darüber alle Arten asynchroner Anfragen (GET, POST und weitere) abstrahiert. Ausgehend von der globalen Funktion fetch(), der man direkt den HTTP-Request übergibt, erhält man ein Promise zurück, das man mittels noch zu definierender Funktion entsprechend bearbeitet:

fetch(url)
  .then(function(response) {
    return response.json();
  })
  .then(function(data) {
    console.log(data);
  })
  .catch(function(error) {
    console.error(error);
  });
 
 
Das Arbeiten mit Axios eignet sich besonders in Fullstack-Entwicklungssträngen, da man die Bibliothek sowohl für die der Verarbeitung von HTTP-Requests am Frontend als auch für die Programmierung am Backend einsetzen kann. Zu Beginn installiert man im Entwicklungsprojekt das npm-Package: npm install axios --save.

Docker erweitert Einsatzoptionen für Nhost-Dienste

Nhost nutzt Docker und Docker Compose zur Bereitstellung seiner Services in der Cloud und für lokale Umgebungen. Docker und Docker Compose unterstützen durch Virtualisierung die Entwicklung, Bereitstellung und Ausführung von Software für verschiedene Virtualisierungsumgebungen. Virtualisierung erleichtert wesentlich die Portierung von Diensten auf unterschiedliche Laufzeitplattformen und erweitert so wesentlich deren Einsatzszenarien.
Die Library macht man entweder über eine Import-Anweisung import axios from ‚axios‘ oder über ein CDN (siehe Teil 3) wie jsDelivr oder UNPKG <script src = "https://unpkg.com/axios/dist/axios.min.js"> </script> zugänglich. Das Objekt axios besitzt Methoden wie get oder put, die man mit den jeweils passenden Parametern aufruft. Anschließend erhält man ähnlich wie beim Fetch-API ein Promise-Objekt zurück, das man mittels then und catch verarbeitet.

HTTP-Server-API mit Axios am Backend in TypeScript programmieren

Nach der Installation des TypeScript-Compilers mittels npm install -g typescript, erzeugt man im backend-Projektordner über npm init -y eine package.json-Datei. Anschließend installiert man im Projektordner die nachfolgenden npm-Packages: typescript ts-node express @types/express axios @types/axios und nodemon.Um eine TypeScript-App mit Node.js auszuführen, benötigt man eine tsconfig.json-Datei; diese erzeugt der Compiler-Aufruf tsc --init, den man im Projektordner absetzt. Die dortigen Einstellungen der Konfiguration des TypeScript-Compilers prüft man auf die nachfolgenden Vorgaben:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "esModuleInterop": true,
        "strict": true,
        "outDir": "./build",
        "rootDir": "./source",
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    }
}
 
 
In der package.json-Datei ändert man den Eintrag im main-Bereich auf "main": "source/server.ts", und erweitert den scripts-Bereich, um die beiden nachfolgenden Vorgaben:

"scripts": {
    "dev": "nodemon source/server.ts",
    "build": "rm -rf build/ &amp;&amp; prettier 
    --write source/ &amp;&amp; tsc"
}
 
 
Damit stößt der Befehl npm run dev den Compile-Vorgang an und startet den Entwicklungsserver. Die Implementierung des HTTP-Servers erfolgt mittels Node und Express in der Datei server.ts: sie stellt die Middleware für Router, JSON-Objekte und Fehlerbehandlung bereit und startet den HTTP-Server auf Port 4711:

// source/server.ts 
import http from 'http';
import express, { Express } from 'express';
import routes from './routes/routes';
const router: Express = express();
// Den Request parsen 
router.use(express.urlencoded({ extended: false }));
// Daten als JSON-Objekt behandeln */
router.use(express.json());
// Die Routes definieren 
router.use('/', routes);
// Fehler-Behandlung fuer die Router aktivieren
router.use((req, res, next) =&gt; {
    const error = new Error('not found');
    return res.status(404).json({
        message: error.message
    });
});
/* Server fuer Router auf Port 4711 starten */
const httpServer = http.createServer(router);
const PORT: any = process.env.PORT ?? 4711;
httpServer.listen(PORT, () =&gt; console.log
(`Der HTTP-Server läuft auf Port: ${PORT}`));
 
 
Das Einrichten der Routes erfolgt im backend-Unterverzeichnis routes in der Datei routes.ts:

// source/routes/todos.ts */
import express from ‚express‘;
import controller from '../controllers/todos';
const router = express.Router();
// Die Routes definieren und mit einer Funktion 
// verbinden
router.get('/todos/:id', controller.getTodo);
router.delete('/todos/:id', controller.deleteTodo);
router.post('/todos', controller.addTodo);
export = router;
 
 
Im Unterverzeichnis controller des backend-Ordners befindet sich die Datei todos.ts, diese setzt http(s)-Aufrufe an den Fake-HTTP-Server jsonplaceholder.typicode.com ab, der das Backend über die Axios-Bibliothek für Clients bereitstellt:

// source/controllers/todos.ts 
import { Request, Response, NextFunction } 
from 'express';
import axios, { AxiosResponse } from 'axios';
interface Todos {
    userId: Number;
    id: Number;
    title: String;
    completed: String;
}
// Ein einzelnes todo lesen
const getTodo = async (req: Request, res: Response, next: NextFunction) =&gt; {
    // Den id des todo ueber req bestimmen
    let id: string = req.params.id;
    // Das gewuenschte todo lesen
    let result: AxiosResponse = await 
    axios.get(`https://jsonplaceholder.typicode.com/
    todos/${id}`);
    let post: Todos = result.data;
    return res.status(200).json({
        // Das todo als JSON-Objekt zurueckliefern
        message: post
    });
};
// Ein todo loeschen 
const deleteTodo = async (req: Request, res: Response, next: NextFunction) =&gt; {
    // Die id des todo ueber req.params 
    //bestimmen
    let id: string = req.params.id;
    // Das todo loeschen 
    let response: AxiosResponse = await 
    axios.delete(`https://jsonplaceholder.
    typicode.com/todos/${id}`);
    // Eine Nachricht als response 
    // zurueckgeben
    return res.status(200).json({
        message: 'todo erfolgreich gelöscht'
    });
};
// Ein todo hinzufuegen
const addTodo = async (req: Request, 
res: Response, next: NextFunction) =&gt; {
    // Die Daten ueber req.body bestimmen
    let title: string = req.body.title;
    let body: string = req.body.body;
    // Ein todo hinzufuegen
    let response: AxiosResponse = await axios.
    post('https://jsonplaceholder.typicode.com/todos', {
        title,
        body
    });
    // Die Daten des hinzugefuegten todos zurueckliefern
    return res.status(200).json({
        message: response.data
    });
};
export default { getTodo, deleteTodo, addTodo };
 
 
Die ab diesem Zeitpunkt über das Backend verfügbaren HTTP-Dienste testet man in VSCodium (VS Code) mit dem REST-Client, die zugehörigen HTTP-Aufrufe befinden sich in der Datei test.http:

GET http://localhost:4711/todos/3
 
DELETE http://localhost:4711/todos/4
 
POST http://localhost:4711/todos
 
{
    "title": "Neuer Titel",
    "completed": "false"
}
 
 
Entgegen der Suggestion im Namen erfordert Serverless Computing auch weiterhin Server, allerdings stellen diese die Hersteller der Backend-as-a-Service (BaaS)-Plattformen über die Cloud bereit. Als Anwender muss man sich keinerlei Gedanken zur Bereitstellung der Infrastruktur der dahinterliegenden Server machen. Das Aufsetzen und Skalieren verbunden mit der benötigten Verfügbarkeit und Fehlertoleranz der Server übernimmt vollständig der Serviceanbieter, also der Hersteller der jeweiligen BaaS-Plattform.

Serverless-SDK mit Backend-as-a-Service in der Cloud für App nutzen

Jede App erhält alle benötigten Ressourcen vom Provider zugewiesen und skaliert im Bedarfsfall automatisch. Die Abrechnung der genutzten BaaS-Dienste erfolgt über die tatsächlich verbrauchten Rechen- und Speicherressourcen. Die sicherlich größte Gefahr für einen Anwender beim Serverless Computing stellt die Herstellerabhängigkeit dar, da die App in der Regel spezifische Schnittstellen des jeweiligen BaaS-Produkts nutzt. Richtet man eine komplette Anwendungslandschaft auf ein bestimmtes BaaS-Produkt aus, so bindet man ein hohes Investitionsvolumen an dessen zukünftiges Erfolgspotenzial.Aus Sicht Entwicklungsplattform für mobile und Web-Anwendungen gilt Firebase von Google als der wohl bekannteste BaaS. Firebase stellt ein Software-Development-Kit (SKD) mit seinen Tools bereit, die Entwickler in ihren Apps einbinden können. Aufgrund der proprietären Ausrichtung von Firebase hat die Open-Source-Gemeinde begonnen, Alternativen für Firebase zu entwickeln. So starteten 2019 in Schweden Nhost und in den USA Supabase auf der Basis von Open-Source-Produkten mit ihren BaaS-Diensten.

Unterscheidungsmerkmale der Serverless-SDKs herausarbeiten

Im Unterschied zur NoSQL-Datenbank in Firebase nutzen sowohl Nhost als auch Supabase das DBMS PostgreSQL für die Datenhaltung. Neben der Postgres-Datenbank stehen in Nhost als weitere Dienste: Authentifizierung und Autorisierung, Storage/Speicher, Realtime-, REST- und GraphQL-APIs sowie Deployment zur Verfügung; zusätzlich sind Serverless Functions angekündigt. GraphQL und GitHub-Integration stellen die Alleinstellungsmerkmale von Nhost dar; während Firebase und Supabase auf REST fokussieren. Die Stärken von Firebase liegen vor allem in den integrierten Marketing-Features. Damit kann man in die zu entwickelnde App umfangreiche Analysen, A/B-Testing und Marketing-Kampagnen integrieren. Mit diesen lässt sich das Benutzerverhalten besser verstehen und zielorientiert beeinflussen.Die Verwaltung aller drei Produkte Firebase, Supabase und Nhost erfolgt über deren Host-Plattform in der Cloud. Dabei handelt es sich technisch gesehen um eine Web-App, die man als Entwickler für den Aufbau, Analyse und Verwaltung der Infrastruktur einer App einsetzt (Bild 7). Anhand der bereitgestellten Benutzeroberfläche, auch Konsole genannt, definiert man ein Projekt, ordnet diesem, Benutzer/Teammitglieder, Speicherbereiche und die für das Projekt gewünschten Services zu.
Einrichten und Verwalten eines Projektsmit einem Serverless-Backend erfolgt über deren Benutzeroberfläche/Konsole in einer Web-App(Bild 7) © Simon
Für das Arbeiten mit der Konsole benötigt man einen Account auf der Host-Plattform des jeweiligen Herstellers. Firebase verlangt die Einrichtung eines Google- und Supabase einen GitHub-Account; für Nhost verwendet man einen bestehenden GitHub-Account oder legt einen eigenständigen Account an. Dabei erfordert die Entwicklung der App keine bestimmte Entwicklungsumgebung; auch kann man jedes beliebige Framework verwenden. Für die Programmierung einer Ionic-App stellen alle drei BaaS eine spezielle JavaScript-Library bereit.

Infrastruktur für Cloud-Backend auf Basis von Nhost einrichten

Zu Beginn benötigt man einen Account auf Nhost, um das Backend auf der BaaS-Plattform einzurichten und bereitzustellen. Im ersten Schritt legt man den Nhost-Account an, definiert anschließend ein Projekt und wartet bis die Verfügbarkeitsanzeige über den Status aller links angezeigten Bestandteile/Nhost-Services auf grün steht. Um über Hasura eine PostgreSQL-Datenbank anzulegen, öffnet man das neue Projekt, wählt die Registerlasche Hasura aus, kopiert den ADMIN SECRET und klickt auf die Schaltfläche Open Hasura Console. Beim ersten Login übergibt man durch Paste/Einfügen die kopierte ADMIN SECRET in das Eingabefeld Enter admin-secret.In der Hasura Console legt man über die Registerlasche DATA eine Tabelle durch Klick auf Add Table an. Als Name der Tabelle vergibt man Angest, wählt über Frequently used columns das id-Feld als Primärschlüssel aus und definiert name als Spalte vom Typ Text.Ein Klick auf die Schaltfläche Add Table legt die neue Tabelle Angest mit automatischem Primärschlüssel und der Spalte name in der Datenbank an. Die unterhalb der Tabelle Angest angezeigten Registerlaschen (Bild 8) zeigen alle Sätze der Tabelle an, fügen neue Sätze in die Tabelle ein, verändern die Daten bestehender Sätze, legen Beziehungen zwischen den Tabellen über Fremdschlüssel an oder vergeben Berechtigungen anhand von Rollen.
Hasura dient Nhost als GraphQL Server– beginnend mit Postgres als Backend für die Datenhaltung(Bild 8) © Simon
Die Hasura Console besitzt eine GraphiQL-Schnittstelle, dabei handelt es sich um eine interaktive GraphQL-IDE, zum Erkunden des Schemas einer Datenbank oder zum Ausführen von Abfragen auf der Datenbank. Links neben der Registerlasche DATA öffnet ein Klick auf GRAPHIQL diese GraphQL-IDE. In der Liste Explorer erschienen alle in der Datenbank vorhandenen Tabellen.Klickt man in dieser Liste die soeben angelegte Tabelle Angest an, so erscheinen als Checkboxen die vorhandenen Attribute – die man anschließend in die neue Abfrage MyQuery übernimmt. Der Ausgabebereich GraphiQL neben Explorer zeigt die aktuell spezifizierte Abfrage an, die ein Klick auf das danebenstehende Pfeil-Icon ausführt. Anschließend gibt GraphiQL neben der Query-Definition die Ergebnisse der Query-Ausführung aus.

Backend-Ordner mit Nhost-BaaS für lokale Entwicklung bereitstellen

Nhost unterstützt eine Entwicklung in einer lokalen IDE, die der Programmierer mittels des Nhost CLIs nutzt. Dazu richtet man nhost als globales npm-Package: npm install -g nhost ein. Zusätzlich müssen noch das Hasura CLI, Docker und Docker Compose installiert sein. Die Version des installierten Hasura CLIs muss mindestens der über Nhost dem Projekt zugeordneten Version entsprechen. Die benötigte Angabe befindet sich in der Nhost-Konsole des Projekts beim Register Hasura. Eine Installation nimmt der Befehl npm install --global hasura-cli@1.3.3 vor. Abschließend lädt man noch Docker Deskop herunter, darin ist Docker Compose enthalten, und führt die Installation durch.Anschließend öffnet man ein Terminal-Fenster/Eingabeaufforderung, legt einen nhost-Ordner im backend-Verzeichnis des Entwicklungsprojekts an und gibt dort den CLI-Befehl nhost login ein. Dieser Befehl führt ein Remote-Login auf Nhost durch; dazu gibt man die zugehörige E-Mail-Adresse ein und bestätigt die Anmeldung über eine zuvor erhaltene E-Mail. Gibt man jetzt den CLI-Befehl nhost init ein, so erzeugt dieser die initialen Konfigurationsdateien im Nhost-Account und verbindet diese mit einem Projekt in der Nhost-Cloud für eine lokale Entwicklung mit Nhost. Dazu verlangt der init-Befehl die konkrete Auswahl eines Nhost-Projekts (Select Projekt (Use arrow keys)), um für dieses Projekt die passenden Konfigurationsdateien im nhost-Ordner abzulegen. Dazu gehören alle Information der von diesem Projekt im jeweiligen Account angelegten Ressourcen der BaaS-Dienste mit ihren Metadaten. Die config.yaml-Datei listet alle Versionen der BaaS-Dienste mit den zugehörigen Ports auf. In der Datei .env.development trägt man alle relevanten Umgebungsvariablen für Nhost ein.Nachdem man Docker Desktop gestartet hat, bringt der CLI-Befehl nhost dev die lokale Nhost-Entwicklungsumgebung zur Ausführung – es erscheint die Ausgabe: Local Nhost backend is up! mit weiteren Informationen zur Verbindung mit dem GraphQL API, der Hasura Console, dem Auth & Storage sowie dem Custom API. Nach Ausführung des nhost dev-Befehls startet die Hasura Console automatisch im Webbrowser; diese erreicht man http://localhost:9695. Des Weiteren erreicht man das GraphQL API über http://localhost:8080/v1/graphql, Auth & Storage: http://localhost:9001 und das Custom API: http://localhost:4000. Das Custom API befindet sich derzeit noch im Beta-Status.

GraphQL kennt grundsätzlich drei Anweisungstypen

GraphQL spezifiziert Anweisungen über ihren Typ, Tabellen-, Feldnamen und weiteren Parametern/Variablen. In GraphQL stehen Queries für Abfragen, Mutations für Änderungen und Subscriptions zum Abonnieren von Änderungen an Daten zur Verfügung. Bei einer Subscription erzeugt der GraphQL-Server bei Änderungen in den Daten push-Nachrichten, welche die Anwendung entsprechend verarbeitet. Alle drei Anweisungstypen kann man mit zusätzlichen Parametern/Variablen versehen, deren Wert man entsprechend von außen setzt.
Das docker logs-Kommando erzeugt lokale Protokolle für jeden der BaaS-Dienste von Nhost. Die wichtigsten Dateien für das lokale Arbeiten mit Nhost befinden sich im nhost-Verzeichnis des backend-Projektordners. Das Nhost-Projekt verbindet man über das Settings-Register durch Auswahl von Git Integration mit einem GitHub-Repository und Klick auf die Save-Schaltfläche. Abschließend verknüpft der Befehl nhost link den nhost-Ordner im backend-Projektverzeichnis mit dem durch Auswahl festgelegten Nhost-Projekt. Der Befehl nhost down beendet alle Dienste von Nhost auf einer lokalen Entwicklungsmaschine und gibt die zugeordneten Ports wieder frei.

Projektordner mit Ionic-App für Programmierung mit Nhost aufbauen

Das zu programmierende Beispielprogramm für Ionic/Vue stellt ein Formular dar, das neue Benutzer zusammen mit deren Kennwort auf Nhost einrichtet. Zu Beginn legt der Befehl ionic start frontend blank --type=vue ein neues Verzeichnis frontend an und generiert in dieses eine Ionic/Vue-App mit blank als Starter-Template. Für die Entwicklung des Frontends einer Ionic-App auf der Basis eines Cloud-Backends wie Nhost installiert man im frontend-Verzeichnis alle seitens Nhost benötigten Bibliotheken. Diese ergeben sich aus den zu erledigenden Aufgaben der Ionic-App. Abhängig von den seitens Nhost in der Ionic-App zu nutzenden Funktionalitäten stehen die nachfolgenden npm-Packages zur Auswahl:Nhost stellt seine Dienste als BaaS jeder App ständig zur Verfügung, da Nhost als Server immer im Web läuft. Somit entfällt für die Entwicklerorganisation das komplette Management der Infrastruktur. Es muss auch kein Webbrowser mit nhost.io geöffnet oder gar ein Login an der Nhost Console ausgeführt werden. Die Funktionalität zur Neuanlage eines Benutzers mit Passwort befindet sich in der Bibliothek Auth. Die dazu notwendige Installation führt der Befehl npm install --save nhost-js-sdk aus.Die Prüfung der Eingabefelder email und password des Formulars erfolgt mittels der Vuelidate-Bibliothek (siehe Teil 9). Die zugehörigen Bibliotheken installiert der Befehl npm install @vuelidate/core @vuelidate/validators. Im src-Verzeichnis der Ionic/Vue-App legt man einen neuen Ordner utils mit einer Datei nhosts.ts an. Der darin enthaltene Quellcode erzeugt die Client-Schnittstelle für den betroffenen Nhost-Account. Dazu bedient sich die Methode createClient() einer Nhost-Konfiguration config. Die notwendige baseURL kopiert man sich über den Nhost-Account im Dashboard beim Eintrag Backend (auth & storage). Nach Außen gibt nhost.ts über das export-Statement die beiden Konstanten auth und storage bekannt:

// nhosts.ts
import { createClient } from "nhost-js-sdk";
const config = {
  baseURL: "https://backend-XXXXXXXX.nhost.app",
};
const { auth, storage } = createClient(config);
export { auth, storage };
 
 
Die Neuanlage eines Benutzers für das Projekt im Cloud-Backend Nhost erfolgt über eine Funktion adduser. Diese übergibt man den neu anzulegenden Benutzer, der aus einer E-Mail-Adresse und einem Kennwort besteht. Dazu erzeugt die Methode register des nhost-js-skd mittels des auth-Objekts auf Nhost im gewünschten Account anhand der übergebenen Parameter einen neuen Benutzer:

// adduser.ts
import { auth } from "./nhost";
 
export function adduser(email: string, password: string) {
        auth.register({ email, password })
}
 
 
Das gewünschte Eingabeformular baut man innerhalb eines <form>-Tag-Bereichs mit den Ionic-Komponenten auf. Dazu greift man auf die IonLabel- und IonInput-Komponente zurück. Das Eingabefeld E-Mail-Adresse erhält den Namen email, den type email und als Platzhalter soll die Zeichenkette name@firma.com erscheinen. Entsprechend erfolgt die Definition des Eingabefelds Passwort/Kennwort (name: password und type: password). Für Ionic/React stellt Nhost eine eigene React-Komponente im npm-Package @nhost/react-auth für die Authentifizierung bereit: NhostAuthProvider. Dieser React-Komponente übergibt man {auth} als Parameter, in dem sich das Objekt nhostClient.auth befindet.Beide Eingabefelder email und password erhalten eine Verknüpfung zu den data()-Felder der VueComponente Home. Damit stehen diese über das v-model dieser VueComponente zur Verfügung.Die Überprüfung mittels Vuelidate erfolgt für beide Eingabefelder innerhalb eines <div>-Tags mittels einer v-if-Anweisung. Den eigentlichen Speicher-Vorgang stößt ein Klick auf die Schaltfläche Benutzer hinzufügen an:

&lt;form&gt;
    &lt;ion-item&gt;
        &lt;ion-label&gt;E-Mail-Adresse: &lt;/ion-label&gt;
        &lt;ion-input name="email" type="email"
        placeholder="name@firma.com" v-model="v$.
        email.$model"&gt;&lt;/ion-input&gt;
        &lt;div v-if="v$.email.$error"&gt;E-Mail-Adresse 
        enthält einen Fehler!&lt;/div&gt;
        &lt;ion-label&gt;Passwort/Kennwort&lt;/ion-label&gt;
        &lt;ion-input name="password" type="password"
        placeholder="Kennwort" v-model=
        "v$.password.$model"&gt;&lt;/ion-input&gt;
        &lt;div v-if="v$.password.$error"&gt;Passwort 
        mindestens 7 Zeichen!&lt;/div&gt;
    &lt;/ion-item&gt;
    &lt;p&gt;
      &lt;ion-button @click="submitForm"&gt;  
          Benutzer hinzufügen
      &lt;/ion-button&gt;
    &lt;/p&gt;
&lt;/form&gt;
 
 
Die Initialisierung von Vuelidate erfolgt bei der Definition der Vue-Komponente Home im setup()-Bereich. Dort definiert der validations()-Bereich die durchzuführenden Prüfungen für die Eingabefelder email und password. Beide Eingabefelder stellen Mussfelder dar; zusätzlich entspricht email dem Vuelidate-Typ email und password muss aus mindestens 7 Zeichen bestehen. Die Überprüfung auf der Länge von 7 Zeichen übernimmt minLength(7) aus Vuelidate:

validations() {
    return {
      email: { required, email},
      password: { required, minLength: minLength(7)},
    }
  }
 
 
Als Click-Event-Handler bei der Schaltfläche Benutzer hinzufügen ist "submitForm" definiert. Deren Programmierung erfolgt bei der VueComponent-Definition im methods-Bereich. Zunächst überprüft ein if-Statement, ob beide Felder email und password einen Eingabewert besitzen. Sind beide Eingabefelder gefüllt, führt der Aufruf von adduser die Neuanlage eines Benutzers im Nhost-Backend aus. Anschließend erfolgt eine Informationsmeldung, dass die Verarbeitung stattgefunden hat, beide Eingabefeld werden mittels $touch() von Vuelidate auf ungeprüft zurückgesetzt und mit den Vorgabewerten versehen:

methods: {
    submitForm () {
        // Alle Eingaben ueberpruefen
        this.v$.$validate();
        if (!this.v$.$error) { 
            // Alle Eingaben korrekt
            adduser(this.v$.email, this.v$.password);
            alert('Verarbeitung hat stattgefunden'!);
            // Eingabefelder auf ungeprüft zurücksetzen
            this.v$.email.$touch();
            this.v$.password.$touch();
      } else {
            alert('Richtige Eingabefelder eingeben!')
      }
    }
  }
 
 
GraphQL spezifiziert eine Abfrage- und Manipulationssprache mit einer serverseitigen Laufzeitumgebung. Die Konzeption von GraphQL fand 2012 bei Facebook mit dem Ziel statt, bestehende Schwächen von REST und SOAP zu beseitigen. Ende 2018 übertrug Facebook die Rechte von GraphQL der neu gegründeten GraphQL Foundation, die inzwischen von Facebook in die gemeinnützige Linux Foundation ausgegliedert wurde. Bibliotheken für Zugriffe auf einen GraphQL-Server gibt es für alle gängigen Programmiersprachen. Nhost realisiert eine GraphQL-Schnittstelle als BaaS über die Hasura GraphQL Engine.Derzeit erfolgt die Datenhaltung auf Nhost in PostgreSQL; wobei Hasura zusätzlich SQL Server, Amazon Aurora und Google BigQuery unterstützt. Für Oracle, MongoDB, MySQL befindet sich GraphQL aktuell im Betastatus. Beim Einsatz von GraphQL bietet Nhost über Hasura eine automatisches Backend für jede Client-App an. Somit entfällt im Unterschied zu einer REST-Lösung beim Einsatz von Nhost die Programmierung eines Backends am Server – vielmehr nutzt der Client über GraphQL direkt den automatisch bereitgestellten Endpoint. Am Frontend des Clients muss man lediglich ein npm-Package für den GraphQL-Client installieren und die Zugriffe in JavaScript/TypeScript programmieren.
Ein Klick auf das Copy-to-Clipboard-Iconkopiert den von der Hasura Console generierten Beispielcode anschließend in die Zwischenablage(Bild 9) © Simon
Klickt man in der Hasura Console bei einer GraphQL-Abfrage auf die Schaltfläche Code Exporter, so öffnet sich ein gleichnamiges Dialogfenster. Wählt man anschließend in den beiden Auswahllisten JavaScript und react-apollo sowie die beiden Optionskästchen with client setup und with required imports aus, so erscheint danach im Dialogfenster der zugehörige Quellcode, um die GraphQL-Abfrage in einer React App auszuführen. Das Copy-to-Clipboard-Icon (Bild 9) kopiert den Quellcode in die Zwischenablage. Speziell auf Nhost abgestimmte Beispielprogramme für GraphQL findet man im GitHub-Repository Nhost Examples.

Hauptkomponenten einer GraphQL-App für das Ionic-Frontend

Grundsätzlich greift die Entwicklung einer Ionic-App mit Nhost und GraphQL auf die Apollo-Implementierung zurück. Abhängig vom Typ der Ionic-App benötigt man zusätzliche Bibliotheken für die Programmierung. So stellt Nhost für React und Vue die beiden speziellen npm-Packages @nhost/react-apollo und nhost-vue-apollo zur Verfügung. Darin findet man spezielle Komponenten wie NhostApolloProvider für React oder die Schnittstellen zu den Hooks (useSubscription, useQuery, useMutation) für Vue. Für Angular greift man auf das gängige npm-Package apollo-angular zurück.Zusätzlich benötigt man für jede Ionic-App mit GraphQL immer die npm-Packages graphql, graphql-tag und @apollo/client; abhängig von den in der App seitens GraphQL genutzten Features kommen noch weitere hinzu. Im ersten Schritt führt die Ionic-App eine Authentifizierung für den Benutzer durch; die derzeit wegen den in Hasura definierten Berechtigungen für den Datenzugriff eigentlich nicht notwendig wäre. Allerdings trägt eine Authentifizierung zur mehr Sicherheit bei; welche die Ionic-App über einen createClient-Aufruf aus dem nhost-js-sdk erledigt. Nhost baut so eine Verbindung auf und führt die Authentifizierung für die BaaS über die Umgebungsvariable XXX_APP_BACKEND_ENDPOINT durch:

import { createClient } from "nhost-js-sdk";
const config = {
  baseURL: process.env.XXX_APP_BACKEND_ENDPOINT,
};
const { auth, storage } = createClient(config);
export { auth, storage };
 
 
Diese Umgebungsvariable befindet sich mit XXX_APP_GRAPHQL_ENDPOINT und anderen in der Konfigurationsdatei .env.development, die der nhost init-Befehl zusammen mit weiteren Dateien zu Beginn angelegt hat. Bei Bedarf greift Nhost selbständig auf diese Konfigurationsdatei zu und bestimmt die benötigte Umgebungsvariable. Die eigentliche Authentifizierung erfolgt mittels der login-Methode der auth-Instanz, der man als Parameter die E-Mail-Adresse und das Kennwort des Benutzers übergibt:

try {
      await auth.login({ email, password });
    } catch (error) {
            …
    }
 
Um die GraphQL-Schnittstelle von Hasura zu benutzen, erzeugt man einmalig innerhalb der Ionic-App einen ApolloClient. Alternativ nutzt man die für das jeweilige Framework Angular, React oder Vue speziell für Apollo verfügbaren Komponenten. ApolloClient beziehungsweise die Framework-Komponenten verwalten die seitens GraphQL spezifizierten Schnittstellenobjekte wie den cache oder die URI auf den GraphQL-Endpoint:

const GET_TODOS = gql`
      subscription {
        todos {
          id
          created_at
          name
          is_completed
        }
      }
    `;
…
// Ausfuehrung der GraphQL-Anfrage ueber 
// einen Hook in Vue
let { onResult } = useSubscription(GET_TODOS);
    onResult((result) =&gt; {
      todos.data = result.data;
    });
return {
      todos,
    };
 
Die auszuführende GraphQL-Anweisung deklariert ein gql-Tag mittels einer Konstante, die man zur Ausführung über Hasura an eine Komponente oder Hook des jeweiligen Frameworks übergibt. In deren data-Bereich befinden sich die Ergebnisse der GraphQL-Abfrage.

Links zum Thema

◼ <b><a href="https://ionicframework.com/" rel="noopener" target="_blank">Homepage von Ionic</a> </b>

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige