<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Deduce]]></title><description><![CDATA[Artikel rund um das Thema AI & ML]]></description><link>https://deduce.de/</link><image><url>https://deduce.de/favicon.png</url><title>Deduce</title><link>https://deduce.de/</link></image><generator>Ghost 4.2</generator><lastBuildDate>Sun, 12 Apr 2026 09:06:53 GMT</lastBuildDate><atom:link href="https://deduce.de/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Flask: Backend Services in Python]]></title><description><![CDATA[In diesem Artikel geht es um die Grundlagen des Python Frameworks Flask. Fokus ist die Nutzung von Flask als Backend Service. Ich werde grundlegende Konzepte mit Beispielen erläutern und auf die Anbindung einer Datenbank, sowie die Serialisierung von Daten eingehen. ]]></description><link>https://deduce.de/flask-backend-services-in-python/</link><guid isPermaLink="false">61d2e60d9394f37db13b9f1d</guid><category><![CDATA[Flask]]></category><category><![CDATA[Python]]></category><category><![CDATA[Backend]]></category><dc:creator><![CDATA[Sebastian Wette]]></dc:creator><pubDate>Mon, 03 Jan 2022 12:30:00 GMT</pubDate><media:content url="https://deduce.de/content/images/2022/01/steve-johnson-dVRD8E3XUGs-unsplash--1-.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="inhalt">Inhalt</h1>
<ol>
<li><a href="#intro">Einf&#xFC;hrung</a></li>
<li><a href="#setup">Setup</a></li>
<li><a href="#basic">Eine grundlegende Flask-Applikation</a></li>
<li><a href="#db">Datenbankanbindung und Serialisierung</a></li>
<li><a href="#endpoints">Grundlegende CRUD Endpunkte</a></li>
<li><a href="#links">Weiterf&#xFC;hrendes Material</a></li>
</ol>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="einf%C3%BChrunga-nameintroa">Einf&#xFC;hrung<a name="intro"></a></h2>
<img src="https://deduce.de/content/images/2022/01/steve-johnson-dVRD8E3XUGs-unsplash--1-.jpg" alt="Flask: Backend Services in Python"><p>Flask ist ein Python Web-Framework und geh&#xF6;rt mit Django zu den beiden bekanntesten solcher Frameworks. Mit Flask ist es m&#xF6;glich ganze Webseiten zu erstellen, da das Framework z.B. auch mit einer Templating-Engine (JinJa2) daherkommt. In diesem Artikel soll es allerdings nur um die Verwendung von Flask im Backend gehen. Hierzu bietet das Framework viele Funktionlit&#xE4;ten um eine vollwertige REST (Representational State Transfer) API (Application Programming Interface) zu entwickeln.</p>
<p>Das sch&#xF6;ne an Flask ist, dass es erstmal ohne viele, h&#xE4;ufig unbenutzte, Extras l&#xE4;uft und von sehr vielen Entwicklern immer wieder als &#xE4;u&#xDF;erst &quot;lightweight&quot; bezeichnet wird. Dies wird im Vergleich sehr deutlich wenn man sich mal mit Django au&#xDF;einandersetzt. Trotzdem bietet Flask auch viel Extra-Funktionalit&#xE4;t, die durch verschiedenste Module hinzugef&#xFC;gt werden kann. Eines dieser extra Packages ist &quot;SQLAlchemy&quot; welches ich auch in den folgenden Beispielen verwenden werde um eine Datenbank einzubinden. Was w&#xE4;re ein Backend schon ohne Datenbank. Ein weiteres interessantes Package, welches auch in den Beispielen wichtig wird, ist &quot;Marshmallow&quot;. Es wird verwendet um Objekte in Python-Datentypen zu konvertieren, und andersherum. Man spricht hier auch von &quot;Serialisierung&quot;. H&#xE4;ufig sieht man Marshmallow im Verwendung zusammen mit SQLAlchemy.</p>
<p>Ich sollte noch erw&#xE4;hnen, dass ich in dieser Arbeit nicht auf einige &quot;fortgeschrittene&quot; Features einer Backend REST API, wie z.B. ein User-Login System, eingehen werde, sondern mich auf die Kerninhalte einer simplen REST API beschr&#xE4;nke. Am Ende des Artikels werde ich aber einige Quellen verlinken, die noch tiefer in die Materie tauchen und beispielsweise auch auf Module eingehen, die solche Login Systeme bereits abdecken.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="setupa-namesetupa">Setup<a name="setup"></a></h2>
<p>Um mit Flask zu arbeiten bietet es sich, wie bei eigentlich jedem Python Projekt, an eine virtuelle Umgebung aufzusetzen, um so einen &#xDC;berblick &#xFC;ber die Abh&#xE4;ngigkeiten des Projektes zu behalten. Voraussetzung hierf&#xFC;r ist der Package Installer for Python (kurz PIP). F&#xFC;r virtuelle Umgebungen verwende ich das Paket &quot;virtualenv&quot;, aber es gibt nat&#xFC;rlich noch andere Optionen. Installiert wird das Paket mit folgendem Befehl:</p>
<pre><code class="language-bash">pip3 install virtualenv
</code></pre>
<p>Als n&#xE4;chstes muss man eine neue Umgebung erstellen:</p>
<pre><code class="language-bash">python3 -m venv &lt;path to new environment&gt;/&lt;env-name&gt;
</code></pre>
<p>Nun wird automatisch ein Ordner f&#xFC;r die neue Umgebung erstellt, in dem einige Scripts abgespeichert sind und in dem sp&#xE4;ter auch alle Abh&#xE4;ngigkeiten gespeichert werden. Jetzt muss man die Umgebung noch aktivieren, um sie zu nutzen. Das geschieht unter Linux/Mac mittels:</p>
<pre><code class="language-bash">source &lt;env-name&gt;/bin/activate
</code></pre>
<p>Unter Windows sieht das ganze so aus:</p>
<pre><code class="language-bash">&lt;env-name&gt;\Scripts\activate
</code></pre>
<p>Jetzt ist die Umgebung aktiv und es k&#xF6;nnen Pakete installiert werden. Es folgen alle Pakete die f&#xFC;r die Beispiele installiert werden m&#xFC;ssen:</p>
<pre><code class="language-bash">pip3 install flask flask-sqlalchemy flask-marshmallow marshmallow-sqlalchemy
</code></pre>
<p>Mit PIP ist es m&#xF6;glich eine Liste aller in einer Umgebung installierten Paktete zu erzeugen:</p>
<pre><code class="language-bash">pip3 freeze
</code></pre>
<p>Dieser Befehl erzeugt die Datei &quot;requirements.txt&quot; So kann man sp&#xE4;ter aus dieser Liste heraus alle benn&#xF6;tigten Komponenten installieren:</p>
<pre><code class="language-bash">pip3 install -r requirements.txt
</code></pre>
<p>Um API Endpunkte zu testen kann man sp&#xE4;ter entweder seinen Browser nutzen, oder man greift auf ein Tool wie z.B. Postman zur&#xFC;ck. Das ist aber nat&#xFC;rlich jedem selbst &#xFC;berlassen.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="eine-grundlegende-flask-applikationa-namebasica">Eine grundlegende Flask-Applikation<a name="basic"></a></h2>
<p>Eine REST API wird (meistens) in mehrere Endpunkte gegliedert. Jeder Endpunkt liefert oder empf&#xE4;ngt gewisse Ressourcen. Dies geschieht in der Regel im JSON Format. Wie bereits erw&#xE4;hnt braucht es nicht viel um eine sehr simple Flask Applikation zum laufen zu bringen, da man sehr intuitiv Endpunkte definieren kann.</p>
<p>Fangen wir aber noch schlanker an. Im folgenden Beispiel wird eine Flask Applikation, ohne jegliche Funktionalit&#xE4;t, gebaut und &#xFC;ber einen Developement-Server gestartet. Dazu muss erw&#xE4;hnt werden, dass dieser Server nicht f&#xFC;r Produktionszwecke geeignet ist. Hier sollte man auf eine andere L&#xF6;sung, wie beispielsweise das Hosting via UWSGI, zur&#xFC;ckgreifen. Nun aber zum Beispiel:</p>
<pre><code class="language-python">from flask import Flask

#App initialisieren
app = Flask(__name__)

#Developement-Server starten
if __name__ == &quot;__main__&quot;:
    app.run(debug=True)
</code></pre>
<p>Wenn diese Datei nun mit Python ausgef&#xFC;hrt wird, startet der Server und die Anwendung ist unter &quot;localhost:5000/&quot; erreichbar.</p>
<p>Eine einfache Route erzeugt man wie folgt:</p>
<pre><code class="language-python">from flask import Flask, jsonify

#App initialisieren
app = Flask(__name__)

#Routen
@app.route(&quot;/&quot;, methods=[&apos;GET&apos;])
def home():
    return jsonify({&apos;message&apos;:&apos;hello&apos;})
    
#Developement-Server starten
if __name__ == &quot;__main__&quot;:
    app.run(debug=True)
</code></pre>
<p>Was genau passiert hier? Es wird eine Route mit der dazugeh&#xF6;rigen Funktionalit&#xE4;t definiert. Daf&#xFC;r erstellt man mit einem Flask-eigenen Decorator die Route und legt die HTTP Methoden fest, welche auf diese Route anwendbar sind. Unterhalb dieses Decorators definiert man dann die dazugeh&#xF6;rige Funktionalit&#xE4;t in einer Funktion. Ein solche Funktion liefert immer einen String. In diesem Fall, und im Falle der meisten REST API&apos;s, wird in diesem String aber JSON zur&#xFC;ckgegeben. In Python kann man JSON sehr einfach mit einem Dictionary darstellen, welches dann mit der Funktion &quot;jsonify()&quot; geparsed wird.</p>
<p>Ruft man nach Ausf&#xFC;hren der Datei nun den Localhost am Port 5000 auf, egal ob im Browser, oder mit Postman, wird man {&apos;message&apos; : &apos;hello&apos;} im JSON Format dargestellt sehen k&#xF6;nnen.</p>
<p>Allein mit dieser Funktionalit&#xE4;t l&#xE4;sst sich schon viel anstellen, vor allem da man in Python sehr einfach mit Dictionaries arbeiten kann. Aber nat&#xFC;rlich wollen wir noch ein wenig tiefer in die Materie eintauchen. Daher komme ich jetzt zur Datenbankanbindung und Serialisierung.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="datenbankanbindung-und-serialisierunga-namedba">Datenbankanbindung und Serialisierung<a name="db"></a></h2>
<p>Um eine Datenbank an eine Flask-Applikation anzubinden eignet sich SQL-Alchemy, da es hier ein extra Paket zur Verwendung mit Flask gibt. SQL-Alchemy implementiert einen sogenannten ORM (Object-Relational-Mapper), welcher eine weitere Abstraktionsebenene zwischen der Applikation und der Datenbank (SQL) darstellt. Man kann diesen ORM wie ein gew&#xF6;hnliches Objekt, ganz nach allen Regeln des OOP, verwenden und seine Datenbank ohne SQL Queries verwalten. Man verwendet hierf&#xFC;r die Methoden und Attribute des ORM. Diese extra Abstraktionsebene erm&#xF6;glicht es uns als Endnutzern, unseren Code zur Datenbankinteraktion zu schreiben OHNE uns vorher auf eine bestimmte Datenbank festlegen zu m&#xFC;ssen, da SQL-Alchemy&apos;s Interface mit den meisten g&#xE4;ngigen SQL Datenbanken zurechtkommt. In den weiteren Beispielen verwende ich beispielsweise SQLite, was sich super zum schnellen, lokalen Testen und Entwickeln eignet. Um in Produktion zu gehen kann man dann aber ohne Probleme auf eine MySQL, oder MariaDB Datenbank umsteigen.</p>
<p>Die Daten aus der Datenbank kann man nun als Klasse darstellen lassen, m&#xF6;chte sie aber vielleicht auch als einfache Datentypen ausgeben k&#xF6;nnen. Hierf&#xFC;r verwenden wir Marshmallow um die Daten zu Serialisieren. Daf&#xFC;r erstellt man ein festes Schema, nach welchem Marshmallow dann automatisch umformen kann.</p>
<p>Es folgt ein gr&#xF6;&#xDF;eres Beispiel, an welchem gleich die Prinzipien von SQLAlchemy und Marshmallow erkl&#xE4;rt werden:</p>
<pre><code class="language-python">from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os

#App initialisieren
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))

#Datenbank Setup
app.config[&apos;SQLALCHEMY_DATABASE_URI&apos;] = &apos;sqlite:///&apos; + os.path.join(basedir, &apos;db.sqlite&apos;)
app.config[&apos;SQLALCHEMY_TRACK_MODIFICATIONS&apos;] = False

#Datenbank initialisieren
db = SQLAlchemy(app)

#Marshmallow initialisieren
ma = Marshmallow(app)

#Modell f&#xFC;r eine Task-Ressource
class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True)
    description = db.Column(db.String(200))
    
    def __init__(self, name, description):
        self.name = name
        self.description = description
        
#Task Schema
class TaskSchema(ma.Schema):
    class Meta:
        fields = (&apos;id&apos;,&apos;name&apos;,&apos;description&apos;)

#Schema initialisieren        
task_schema = ProductSchema(strict=True)
tasks_schema = ProductSchema(many=True, strict=True)

#Developement-Server starten
if __name__ == &quot;__main__&quot;:
    app.run(debug=True)
</code></pre>
<p>Zu Beginn m&#xFC;ssen einige Konfigurationen f&#xFC;r die Datenbank vorgenommen werden. Am wichtigsten ist hier die &quot;DATABASE_URI&quot;. Diese URI ist quasi der Pfad zur Datenbank. Je nach verwendeter Datenbank muss diese URI nat&#xFC;rlich angepasst werden, um z.B. auch Nutzerdaten mit zu &#xFC;bergeben. Desweiteren m&#xFC;ssen sowohl SQLAlchemy als auch Marshmallow initialisiert werden.</p>
<p>Nun benn&#xF6;tigt der ORM ein Modell der Daten, welche in der Datenbank abgebildet werden. In unserem Fall ist das die Ressource &quot;Task&quot;. Ein Task besteht aus einer ID, welche auch der Primary-Key ist, dem Namen und einer kurzen Beschreibung. Au&#xDF;erdem braucht das Modell noch einen Konstruktor, in dem diese Werte dem &quot;Objekt&quot; zugewiesen werden. Man beachte, dass die ID hier nicht zugewiesen wird, da sie von SQLAlchemy automatisch verwaltet wird. In unserem Fall werden nur einfache Datentypen f&#xFC;r die Spalten der Datenbank verwendet, aber nat&#xFC;rlich sind beispielsweise auch Relationships mit SQLAlchemy abbildbar. Mehr dazu findet sich in der offiziellen <a href="https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/">Dokumentation</a>.</p>
<p>Zuletzt muss Marshmallow noch informiert werden, wie das Schema f&#xFC;r die Serialisierung auszusehen hat. Den Gro&#xDF;teil &#xFC;bernimmt es bei so simplen Modellen von alleine, aber in einer Subklasse &quot;Meta&quot; m&#xFC;ssen alle Felder angegeben werden, welche bei der Konvertierung ber&#xFC;cksichtigt werden sollen. Dieses Schema muss jetzt nurnoch initialisiert werden. Hierbei ist darauf zu achten, das Schema f&#xFC;r die Ressource einmal f&#xFC;r die R&#xFC;ckgabe eines einzelnen Objektes, als auch f&#xFC;r die R&#xFC;ckgabe mehrerer Objekte auf einmal zu initialisieren.</p>
<p>Bei gr&#xF6;&#xDF;eren Projekten bietet es sich au&#xDF;erdem an, diese verschiedenen Konfigurationen und Modelle in verschiedenen Dateien zu schreiben.</p>
<p>Falls die Datenbank nicht schon bereit steht l&#xE4;sst sie sich sehr einfach mit Hilfe von SQLAlchemy generieren, sodass alle beschriebenen Modelle als einzelne Tabellen erzeugt werden und einsatzbereit sind. Dazu &#xF6;ffnet man ein neues Terminal und startet eine neue Python Shell. Nun folgt als erstes ein Import der Datenbank aus der geschriebenen Datei (die Datei hei&#xDF;t hier app.py):</p>
<pre><code class="language-bash">from app import db
</code></pre>
<p>Jetzt kann die Datenbank mit einem einfachen Befehl erzeugt werden:</p>
<pre><code class="language-bash">db.create_all()
</code></pre>
<p>Damit werden alle Modelle, die in der Datei beschrieben sind erzeugt und im Falle von SQLite sollte in der aktuellen Directory nun die Datei &quot;db.sqlite&quot; angelegt worden sein.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="grundlegende-crud-endpunktea-nameendpointsa">Grundlegende CRUD Endpunkte<a name="endpoints"></a></h2>
<p>Da das Setup der Datenbank erfolgt ist k&#xF6;nnen die ersten Endpunkte erstellt werden. Die folgenden Beispiele sind der &#xDC;bersicht halber vom Rest des Codes getrennt, m&#xFC;ssen f&#xFC;r eine funktionst&#xFC;chtige API aber nat&#xFC;rlich zum Code &quot;Grundger&#xFC;st&quot; hinzugef&#xFC;gt werden. Wo und wie man eine Route definiert wurde bereits dargestellt.</p>
<p>In den folgenden Beispielen schauen wir die volle Funktionalit&#xE4;t einer klassischen API nach &quot;CRUD&quot; (Create, Read, Update, Delete), anhand des Beispiels der Task-Ressource an. So k&#xF6;nnen am Ende neue Tasks erstellt, aber auch gelesen, geupdated und gel&#xF6;scht werden.</p>
<p>Beginnen wir mit CREATE:</p>
<pre><code class="language-python"># CREATE Task
@app.route(&apos;/task&apos;, methods=[&apos;POST&apos;])
def add_task():
  name = request.json[&apos;name&apos;]
  description = request.json[&apos;description&apos;]

  new_task = Product(name, description)

  db.session.add(new_task)
  db.session.commit()

  return product_schema.jsonify(new_task)
</code></pre>
<p>Ein CREATE Endpunkt funktioniert nat&#xFC;rlich als POST Methode, da neue Daten zum Server &quot;geposted&quot; werden.<br>
Alles was nun getan werden muss, ist die benn&#xF6;tigten Daten aus diesem POST-Request zu lesen. Daf&#xFC;r verwendet man das Attribut &quot;request&quot; und liest aus diesen, wie aus einem Dictionary. Als n&#xE4;chstes erzeugt man ein Objekt, welches man anschlie&#xDF;end zur Datenbank hinzuf&#xFC;gt. Das Hinzuf&#xFC;gen funktioniert in zwei Schritten. Als erstes wird das Objekt der aktuellen Session hinzugef&#xFC;gt, und dann wird diese Session zur Datenbank commited. Der R&#xFC;ckgabewert dieses Endpunktes sollen die einzelnen Attribute der Daten im JSON Format sein. Daf&#xFC;r verwendet man das Marshmallow-Schema, welches man direkt in JSON umwandeln kann. Dieser Endpunkt w&#xE4;re so nun einsatzbereit und kann mit Hilfe von Postman getestet werden.</p>
<p>Als n&#xE4;chstes folgen zwei Endpunkte f&#xFC;r die READ/GET Funktionalit&#xE4;t:</p>
<pre><code class="language-python"># GET (alle Tasks)
@app.route(&apos;/task&apos;, methods=[&apos;GET&apos;])
def get_tasks():
  all_tasks = Task.query.all()
  result = tasks_schema.dump(all_tasks)
  return jsonify(result.data)
  
# GET (einzelner Task)
@app.route(&apos;/task/&lt;id&gt;&apos;, methods=[&apos;GET&apos;])
def get_task(id):
  task = Task.query.get(id)
  return task_schema.jsonify(task) 
</code></pre>
<p>Nat&#xFC;rlich werden diese Endpunkte durch GET-Requests angesprochen. Wenn alle Tasks auf einmal abgefragt werden sollen geht das ziemlich schnell, da man der Datenbank nur den Befehl geben muss um alle Tasks zur&#xFC;ckzugeben. F&#xFC;r solche Queries hat der ORM von SQLAlchemy sehr intuitive Methoden. Anschlie&#xDF;end werden diese Daten nach dem Schema umgeformt und im JSON Format zur&#xFC;ckgeliefert.<br>
F&#xFC;r einen einzelnen Task muss man nun noch einen Query-Parameter &#xFC;bergeben. Im Beispiel wird anhand der ID eines Tasks gesucht. Daf&#xFC;r wird der Methode das ID Parameter mitgegeben, welches aus der URL gelesen wird. Innerhalb des Decorators kann man mit den Zeichen &quot;&lt; &gt;&quot; deutlich machen, dass es sich um Parameter handelt.</p>
<p>Kommen wir zur UPDATE Funktionalit&#xE4;t:</p>
<pre><code class="language-python"># UPDATE
@app.route(&apos;/task/&lt;id&gt;&apos;, methods=[&apos;PUT&apos;])
def update_task(id):
  task = Task.query.get(id)

  name = request.json[&apos;name&apos;]
  description = request.json[&apos;description&apos;]
  
  task.name = name
  task.description = description

  db.session.commit()

  return product_schema.jsonify(task)
</code></pre>
<p>Die Methode eines solchen Enpunkt ist PUT. Prinzipiell verbindet man hier GET und POST ein wenig. Zuerst holen wir und den Task der geupdatet werden soll und lesen dann die neuen Daten aus dem Request. Mit diesen neuen Daten ver&#xE4;ndert man dann das aus der Datenbank geladene Objekt und committed diese Ver&#xE4;nderungen dann wieder. Zum Schluss gibt man dann das Schema des ver&#xE4;nderten Tasks zur&#xFC;ck.</p>
<p>Als letztes schauen wir uns DELETE an:</p>
<pre><code class="language-python"># DELETE
@app.route(&apos;/task/&lt;id&gt;&apos;, methods=[&apos;DELETE&apos;])
def delete_task(id):
  task = Task.query.get(id)
  db.session.delete(task)
  db.session.commit()

  return product_schema.jsonify(task)
</code></pre>
<p>Hierf&#xFC;r verwendet man die DELETE-Methode. Auch bei diesem Endpunkt muss erst einmal der gew&#xFC;nschte Task geladen werden. Dieser kann dann sehr simpel gel&#xF6;scht und die &#xC4;nderungen an der Datenbank committed werden.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="weiterf%C3%BChrendes-materiala-namelinksa">Weiterf&#xFC;hrendes Material<a name="links"></a></h2>
<p>Jetzt ist der Punkt erreicht, an dem die sehr simple CRUD REST API voll funktionsf&#xE4;hig ist. Nat&#xFC;rlich gibt es aber noch weitere Themen um noch tiefer in das Thema einzutauchen. Daher hier einige Links:</p>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uswgi-and-nginx-on-ubuntu-18-04">Hosting mit UWSGI und NGINX</a></li>
<li><a href="https://www.youtube.com/watch?v=PTZiDnuC86g&amp;list=WL&amp;index=2">REST API with Flask by Traversy Media</a></li>
<li><a href="https://www.youtube.com/watch?v=CSHx6eCkmv0">Flask User-Login System by Corey Schafer</a></li>
<li><a href="https://flask.palletsprojects.com/en/2.0.x/">Flask Docs.</a></li>
<li><a href="https://docs.sqlalchemy.org/en/14/">SQLAlchemy Docs.</a></li>
<li><a href="https://marshmallow.readthedocs.io/en/stable/">Marshmallow Docs.</a></li>
</ul>
<p>Ich hoffe ich konnte einigen Lesern mit diesem kurzen Artikel weiterhelfen. Vielen Dank f&#xFC;r&apos;s Lesen!<br>
<a href="http://"></a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Einführung in Angular]]></title><description><![CDATA[In diesem Artikel geht es um die Grundlagen des bekannten Frontend-Frameworks Angular. Ich werde grundlegende Konzepte des Frameworks erleutern und auf die Syntax einzenler "Elemente" eingehen.]]></description><link>https://deduce.de/einfuhrung-in-angular/</link><guid isPermaLink="false">61b71a3c9394f37db13b9d8f</guid><category><![CDATA[Angular]]></category><category><![CDATA[Frontend]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Sebastian Wette]]></dc:creator><pubDate>Mon, 13 Dec 2021 11:00:00 GMT</pubDate><media:content url="https://deduce.de/content/images/2021/12/paul-blenkhorn-tYDjgdmjcz8-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="inhalt">Inhalt</h1>
<ol>
<li><a href="#intro">Einf&#xFC;hrung</a></li>
<li><a href="#cli">CLI und Setup</a></li>
<li><a href="#ordner">Ordnerstruktur</a></li>
<li><a href="#komponenten">Komponenten</a></li>
<li><a href="#interpolation">Attribute und Interpolation</a></li>
<li><a href="#inputs">Inputs</a></li>
<li><a href="#outputs">Outputs und Events</a></li>
<li><a href="#modelle">Modelle</a></li>
<li><a href="#directives">Directives</a></li>
<li><a href="#service">Services</a></li>
<li><a href="#observables">Observables</a></li>
<li><a href="#subjects">Subjects und Subscriptions</a></li>
<li><a href="#http">HTTP Client</a></li>
<li><a href="#forms">Forms</a></li>
<li><a href="#routing">Routing</a></li>
<li><a href="#links">Weiterf&#xFC;hrendes Material</a></li>
</ol>
<!--kg-card-end: markdown--><img src="https://deduce.de/content/images/2021/12/paul-blenkhorn-tYDjgdmjcz8-unsplash.jpg" alt="Einf&#xFC;hrung in Angular"><p></p><!--kg-card-begin: markdown--><h2 id="einf%C3%BChrunga-nameintroa">Einf&#xFC;hrung<a name="intro"></a></h2>
<p>Angular ist ein Frontend-Framework f&#xFC;r Single-Page Applications und basiert grunds&#xE4;tzlich auf TypeScript. Angular l&#xE4;uft Clientseitig, aber wird meist mit einem Backend (z.B. einer REST API) verkn&#xFC;pft um so, effiziente und nutzerfreundliche Web-Apps zu bauen. Angular 13.2.0 ist die neuste Version des Nachfolgers von AngularJS.</p>
<p>Mit Angular lassen sich dynamische Apps und User-Interfaces relativ simpel erstellen, aber trotzdem bietet Angular viele advanced Features, wie einen eingebauten HTTP-Client, RxJS (asynchronous), oder einen eigenen Router.<br>
Die Sprache der Wahl ist TypeScript, wobei die Verwendung der TypeScript-eigenen Features optional ist und auch reines JavaScript verwendet werden kann. Auch wenn Angular dem Entwickler viel Arbeit abnimmt, muss man dennoch viel lernen, da Angular ein gro&#xDF;es und umfangreiches Framework bleibt.</p>
<p>Wie die meisten gro&#xDF;en Frontend-Frameworks (vgl. Vue oder React) basiert Angular auf Komponenten. Komponenten sind Teile der UI, die in ein Template (HTML), die Logik (TypeScript) und die Styles (CSS) aufgeteilt werden. Sie sind wiederverwendbar und werden mit eigens deklarierten XML-Tags in die HTML Templates eingebunden. Mehr dazu im Abschnitt &quot;Komponenten&quot;.</p>
<p>Um einen m&#xF6;glichst angenehmen Einstieg in Angular zu haben ist es vorteilhaft, wenn man schon grundlegende JavaScript (oder sogar TypeScript) Kenntnisse vorweisen kann, allerdings m&#xF6;chte ich hier nichts voraussetzen. Ich w&#xFC;rde behaupten, wenn man schon einmal mit einer &quot;C &#xE4;hnlichen&quot; Sprache gearbeitet hat, sollte man keine Probleme mit den angef&#xFC;hrten Code-Beispielen haben.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="cli-und-setupa-nameclia">CLI und Setup<a name="cli"></a></h2>
<p>Angular kommt mit seinem eigenen CLI (Command-Line-Interface) daher. Dieses wird genutzt um neue Projekte anzulegen, aber auch Komponenten und Services zu erzeugen und einen lokalen Dev-Server zu starten (der nicht f&#xFC;r die Produktion verwendet werden sollte). Vorraussetzung hierf&#xFC;r ist, dass Node auf dem System installiert ist, da npm (der Node-Package-Manager) verwendet wird um Angular zu installieren.</p>
<pre><code class="language-Bash">npm install -g @angular/cli
</code></pre>
<p>Mithilfe der CLI l&#xE4;sst sich nun sehr simpel ein neues Projekt erstellen.</p>
<pre><code class="language-Bash">ng new -my-app --no-strict
</code></pre>
<p>Die Option &quot;--no-strict&quot; ist optional und beschreibt nur, ob die TypeScript Dateien &quot;strenger&quot; kompiliert werden (also die Typangaben strenger durchgesetzt werden). Nun kann man noch w&#xE4;hlen ob man Angular-Routing direkt aktivieren m&#xF6;chte und welche Sprache man f&#xFC;r die Syles verwenden m&#xF6;chte (CSS, SCSS ...).</p>
<p>Um den Dev-Server zu starten verwendet man folgenden Command:</p>
<pre><code class="language-Bash">ng serve
</code></pre>
<p>Nun wird die Angular-App via localhost:4200 bereitgestellt.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="ordnerstruktura-nameordnera">Ordnerstruktur<a name="ordner"></a></h2>
<p>Nach dem Erstellen der ersten App kann die Anzahl der generierten Dateien erst einmal einsch&#xFC;chtern sein. Angular erstellt neben den Source-Files z.B auch Dateien zum tracken der npm-Abh&#xE4;ngigkeiten in der &quot;package.json&quot; Datei, Angular-spezifische Konfigurationen in der &quot;angular.json&quot; Datei und Type-Script Konfigurationen in der &quot;tsconfig.json&quot;.</p>
<p>Der interessantest Ordner ist allerdings der &quot;src&quot; Ordner. Im Ordner &quot;/src/app&quot; werden alle Komponenten und Services, und somit der gesamte Kern der App, Platz finden. Innerhalb des &quot;src&quot; Ordners existiert eine &quot;index.html&quot; Datei, welche der Ausgangspunkt der Angular-App ist. In dieser Datei wird, mit dem Tag &lt;app-root&gt;, die Root-Komponente der Angular App eingebunden, und von hier aus schachteln sich nun alle Komponenten, die man in der App einbringt. Nat&#xFC;rlich kann man innerhalb dieser Datei auch einige Metadaten (z.B. den Titel) ver&#xE4;ndern.</p>
<p>Die &quot;main.ts&quot; Datei ist der Einstiegspunkt in Angular f&#xFC;r die App. Hier wird z.B. das &quot;AppModule&quot; geladen. Man kann sich dieses &quot;Module&quot; aber wie eine Art Hub f&#xFC;r die App vorstellen. Es ist der Zentrale Punkt der App, in den man weitere Module von Angular einbinden kann, um diese dann in seinem Code zu verwenden. Die Datei befindet sich im Order &quot;/src/app&quot;, und in ihr wird vorerst nur der Kern von Angular geladen, aber sp&#xE4;ter k&#xF6;nnen weitere Module und auch Services importiert werden.</p>
<p>Desweiteren fallen bestimmt die vielen Dateien mit &quot;.component&quot; im Namen auf, welche mit den verschiedensten Dateiendungen enden (.css, .html, und .ts). Mit diesen Dateien wird eine Komponente beschrieben. Die Konvention f&#xFC;r die Namensgebung lautet hier &quot;&lt;Komponentenname&gt;.component.&lt;Dateityp&gt;&quot;. Wirklich viel muss man hier nicht beachten, da das CLI diese Dateien beim Erstellen neuer Komponenten automatisch nach diesem Schema benennt. Diese verschiedenen Dateien machen jetzt eine Komponente aus, welche in Logik, Template, und Styles aufgeteilt wird. Es existiert auch eine &quot;.spec.ts&quot; Datei welche f&#xFC;r Tests eine Rolle spielt, aber diese soll an dieser Stelle erst einmal vernachl&#xE4;ssigt werden.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="komponenten-a-namekomponentena">Komponenten <a name="komponenten"></a></h2>
<p>Wie in der Einf&#xFC;hrung bereits beschrieben ist Angular komponentenbasiert. Eine Komponente ist ein in sich geschlossener Teil der UI, allerdings k&#xF6;nnen Komponenten nat&#xFC;rlich auch verschachtelt werden und sind vollkommen wiederverwendbar. Eine Komponente besteht aus einem Template (HTML), der Logik (TypeScript) und den optionalen Styles (z.B. CSS oder SCSS). Die Syntax einer Komponente sieht wie folgt aus:</p>
<pre><code class="language-JavaScript">import { Component } from &apos;@angular/core&apos;;

@Component({
    selector: &apos;app-list&apos;,
    templateUrl: &apos;./list.component.html&apos;,
    providers:  [listService]
})

export class ListComponent implements OnInit{
    /* ... */
</code></pre>
<p>Begonnen wird mit einem Decorator, in welchem wichtige Rahmenbedingungen f&#xFC;r die Komponente festgelegt werden wie z.B. der Selektor, also der Tag, mit dem die Komponente sp&#xE4;ter im HTML Code verwendert werden kann. Auch der Pfad zum HTML-Template der Komponente wird hier festgelegt und das w&#xE4;re auch genauso mit den Styles. Man muss erw&#xE4;hnen, dass Template und Styles auch optional inline direkt im Decorator definiert werden k&#xF6;nnen. Davon ist aus Gr&#xFC;nden der modularit&#xE4;t aber eher abzuraten. Unter dem Keyword Providers werden die Services, welche verwendet werden aufgef&#xFC;hrt. Dazu sp&#xE4;ter mehr.</p>
<p>Auf den Decorator folgt eine relativ normale Klassendefinition. Innerhalb dieser Klasse werden die Methoden und Attribute der Komponente definiert.</p>
<p>Eine neue Komponente kann entweder &quot;per Hand&quot; erzeugt werden oder man verwendet das CLI:</p>
<pre><code class="language-Bash"> ng generate component &lt;Komponentenname&gt;
</code></pre>
<p>Angular k&#xFC;mmert sich hier direkt darum, dass die neue Komponente direkt in der &quot;app.module.ts&quot; Datei eingetragen wird und alle n&#xF6;tigen Imports stattfinden. Optional kann ein Pfad zur Komponente (ausgehend vom Ordner &quot;src&quot;) angegeben werden, unter welchem die Komponente zu finden sein soll. Alle Unterordner zu diesem Pfad werden falls n&#xF6;tig automatisch erstellt. So lassen sich Komponenten logisch verschachteln und steigern so die &#xDC;bersichtlichkeit.</p>
<p>In dieser neu erstellten Komponente kann man nun das Template, die Styles, als auch die Logik definieren. Werfen wir einmal einen Blick auf die &quot;app-root&quot; Komponente:</p>
<pre><code class="language-JavaScript">import { Component, OnInit } from &apos;@angular/core&apos;;

@Component({
    selector: &apos;app-root&apos;,
    templateUrl: &apos;./app.component.html&apos;,
    styleUrls:[&apos;./app.component.css&apos;]
})

export class AppComponent implements OnInit{
    title:string = &apos;angular-app&apos;;
    
    ngOnInit(): void{
    }
}
</code></pre>
<p>Hier wird zus&#xE4;tzlich zum Template-File auch die CSS-Datei f&#xFC;r die Styles angegeben. Durch den angegebenen Selektor kann die Root-Komponente nun in der &quot;index.html&quot; mit genau diesem Tag verwendet werden.</p>
<p>Die Methode &quot;ngOnInit()&quot; ist eine sogenannte Lifecycle-Methode. Im Fall von &quot;ngOnInit()&quot; wird diese Methode also dann ausgef&#xFC;hrt, wenn die Komponente initiiert wird. Eine weitere Lifecycle-Methode w&#xE4;re &quot;ngOnDestroy()&quot;.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="attribute-und-interpolation-a-nameinterpolationa">Attribute und Interpolation <a name="interpolation"></a></h2>
<p>Im oben gezeigten Code der &quot;app-root&quot; Komponente ist der &quot;title&quot; ein Attribut dieser Klasse bzw. dieser Komponente. Eine sehr wichtige Funktionalit&#xE4;t von Angular ist es nun, dieses Attribut dynamisch in das HTML-Template einzubinden, um so auch Variablen aus der Logik im Browser anzeigen zu k&#xF6;nnen. Das ganze wird m&#xF6;glich durch &quot;String-Interpolation&quot;.</p>
<p>Der HTML-Code zum Anzeigen des &quot;title&quot; Attributes sieht so aus:</p>
<pre><code class="language-HTML">&lt;h1&gt; {{title}} &lt;/h1&gt;
</code></pre>
<p>Durch zwei Paar geschweifte Klammern &quot;{{}}&quot; wird deutlich gemacht, dass hier eine TypeScript Expression, welche am Ende einen String liefern muss, ausgef&#xFC;hrt wird. Im Browser wird jetzt nat&#xFC;rlich nicht &quot;{{title}}&quot; angezeigt sondern der Wert des &quot;title&quot; Attributes in der Komponente, also in diesem Fall &quot;angular-app&quot;. Prinzipiell kann jede Art von TypeScript Expression zwischen die beiden geschweiften Klammerpaare geschrieben werden.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="inputs-a-nameinputsa">Inputs <a name="inputs"></a></h2>
<p>Bisher k&#xF6;nnen wir Daten aus den Komponenten im Browser anzeigen lassen. Allerdings ist es auch sehr wichtig Daten in eine Komponente &#xFC;bergeben zu k&#xF6;nnen. Hierf&#xFC;r sind Inputs zu verwenden. Sehen wir uns als Beispiel eine Button-Komponente an, in die man eine Frabe und einen Text quasi wie zwei Parameter &#xFC;bergeben kann:</p>
<pre><code class="language-HTML">&lt;header&gt; 
    &lt;app-button 
        [color]=&quot;green&quot; 
        [text]=&quot;Add&quot;&gt;
    &lt;/app-button&gt;
&lt;/header&gt;
</code></pre>
<p>Das ganze nennt man &quot;Databinding&quot; (&quot;[]&quot; = Input) oder genauer &quot;Propertybinding&quot;. Doch ganz so einfach ist es nat&#xFC;rlich nicht. Wir m&#xFC;ssen der Komponente noch sagen, dass sie diese &quot;Parameter&quot; &#xFC;berhaupt entgegennimmt und wie diese dann verwendet werden. Wie die Werte verwendet werden kommt nat&#xFC;rlich auf den Anwendungsfall an. In diesem Abschnitt gehe ich nur auf die Integration solcher Inputs in der Komponente ein. Der Code hierzu sieht wie folgt aus:</p>
<pre><code class="language-JavaScript">import { Component, OnInit, Input } from &apos;@angular/core&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./button.component.html&apos;,
    styleUrls:[&apos;./button.component.css&apos;]
})

export class ButtonComponent implements OnInit{
    @Input text: string;
    @Input color: string;
    
    constructor(){}
    
    ngOnInit(): void{
    }
}

</code></pre>
<p>Nun k&#xF6;nnen die &#xFC;bergebenen Daten in der Komponente verwendet werden.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="outputs-und-events-a-nameoutputsa">Outputs und Events <a name="outputs"></a></h2>
<p>Wenn es Inputs gibt muss es nat&#xFC;rlich auch Outputs geben. Die einfachste Form eines Outputs ist ein Event im DOM. Angular bietet eine sehr einfache M&#xF6;glichkeit auf Standard-Events zu reagieren:</p>
<pre><code class="language-HTML">&lt;button
    class=&quot;btn&quot;
    (click)=&quot;onClick()&quot;&gt;Text
&lt;/button&gt;
</code></pre>
<p>Auch hier spricht man von &quot;Databinding&quot;, allerdings geht es hier in die andere Richtung (&quot;()&quot; = Output) man spricht eher von &quot;Eventbinding&quot;. Innerhalb der Klammern wird das Event beschrieben, auf welches reagiert werden soll, in diesem Fall ein einfacher Klick. Nat&#xFC;rlich k&#xF6;nnte der Methode hier auch etwas &#xFC;bergeben werden. Darauf folgt die Methode der Komponente, welche daraufhin ausgef&#xFC;hrt werden soll. Innerhalb der Komponente, die zu diesem Template geh&#xF6;rt muss nun also die Methode &quot;onClick()&quot; realisiert werden:</p>
<pre><code class="language-JavaScript">import { Component, OnInit, Input } from &apos;@angular/core&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./button.component.html&apos;,
    styleUrls:[&apos;./button.component.css&apos;]
})

export class ButtonComponent implements OnInit{
    @Input text: string;
    @Input color: string;
    
    constructor(){}
    
    ngOnInit(): void{
    }
    
    onClick(){
        console.log(&quot;Click!&quot;);
    }
}
</code></pre>
<p>Wenn diese Komponente eingebunden wird und der Button geklickt wird, sollte man nun in der Konsole ein &quot;Click!&quot; sehen.</p>
<p>So viel zu Standard-Events. Nun wird es aber n&#xF6;tig sein eigene Events, also eigene Output-Signale, weiterzugeben. Auch das ist mit Angular relativ simpel m&#xF6;glich. Hierzu erstellt man ein Attribut vom Typ &quot;EventEmitter&quot;, welches dann ein Event ausgeben kann:</p>
<pre><code class="language-JavaScript">import { Component, OnInit, Input, Output, EventEmitter } from &apos;@angular/core&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./button.component.html&apos;,
    styleUrls:[&apos;./button.component.css&apos;]
})

export class ButtonComponent implements OnInit{
    @Input() text: string;
    @Input() color: string;
    @Output() btnClick = new EventEmitter();
    
    constructor(){}
    
    ngOnInit(): void{
    }
    
    onClick(){
        this.btnClick.emit();
    }
}
</code></pre>
<p>Das angelegte EventEmitter Attribut wird nun in der &quot;onClick()&quot; Methode &quot;aktiviert&quot; und sendet ein Event an seine Parent-Komponente. Innerhalb der Parent-Komponente kann man dieses Event nun wieder wie bei Standard-Events abfangen:</p>
<pre><code class="language-HTML">&lt;header&gt; 
    &lt;app-button 
        color=&quot;green&quot; 
        text=&quot;Add&quot;
        (btnClick)=&quot;printSomething()&quot;&gt;
    &lt;/app-button&gt;
&lt;/header&gt;
</code></pre>
<p>Nun wird also indirekt &quot;printSomething()&quot; dieser Parent-Komponente aufgerufen wenn der Button geklickt wird. Dabei geht erstmal ein &quot;click&quot; Event an die Button-Komponente, welche das eigens erstelle Event &quot;btnClick&quot; ausl&#xF6;st, welches dann die Methode ausl&#xF6;st.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="modelle-a-namemodellea">Modelle <a name="modelle"></a></h2>
<p>Innerhalb von Angular ist es h&#xE4;ufig eine gute Idee ein Modell von einem behandelten Datenobjekt zu erstellen. Ein einfaches Beispiel hierf&#xFC;r w&#xE4;re eine To-Do Liste. Ein wiederkehrendes Element f&#xFC;r welches ein Datenmodell sinnvoll ist w&#xE4;re hier eine Aufgabe. Modelle werden typischerweise im &quot;app&quot; Ordner erstellt und nach dem Schema &quot;&lt;name&gt;.model.ts&quot; benannt. Prinzipiell ist ein Modell einfach nur eine Klasse, jedoch wird es in TypeScript als &quot;Interface&quot; bezeichnet. Es folgt ein Beispiel:</p>
<pre><code class="language-JavaScript">export interface Task {
  id?: number;
  text: string;
  day: string;
  reminder: boolean;
}
</code></pre>
<p>Dieses Modell kann nun in anderen Teilen der Applikation verwendet werden. Beispielweise f&#xFC;r Services, welche mit Aufgaben arbeiten, oder der HTTP-Client welcher Aufgaben aus dem Backend laden wird.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="directives-a-namedirectivesa">Directives <a name="directives"></a></h2>
<p>Directives sind &quot;Logik-Bausteine&quot; welche teilweise mit Angular ausgeliefert werden, aber auch selbst definiert werden k&#xF6;nnen. Mit ihnen kann das Aussehen, oder das Verhalten von Elementen im DOM (Document Object Model) ver&#xE4;ndert werden. Directives k&#xF6;nnen dann in Elementen eingebaut und mit diesen verwendet werden. Nun folgen einige Beispiele:</p>
<p>Beginnen wir mit &quot;ngStyle&quot;. Hiermit k&#xF6;nnen inline CSS Regeln definiert werden, welche aber auch mit Attributen aus der Komponente (aus der TypeScript-Klasse) gef&#xFC;ttert werden k&#xF6;nnen:</p>
<pre><code class="language-HTML">&lt;button 
    [ngStyle]={&apos;background-color&apos;: &apos;green&apos;} 
    class=&quot;btn&quot;&gt; Text
&lt;/button&gt;
</code></pre>
<p>So wird der Hintergrund des Buttons gr&#xFC;n dargestellt.</p>
<p>Eine &#xE4;hnliche Directive, wie &quot;ngStyle&quot; ist &quot;ngClass&quot;. Mithilfe von &quot;ngClass&quot; kann einem Element dynamisch eine spezielle Klasse zugewiesen werden, um so z.B. spezielle CSS-Regeln auf dieses Element anzuwenden. Es folgt ein Beispiel:</p>
<pre><code class="language-HTML">&lt;div [ngClass]=&quot;{toggled: data.isToggled}&quot;&gt;
    ...
&lt;/div&gt;
</code></pre>
<p>In diesem Beispiel wird dem &quot;div&quot;-Element die Klasse &quot;toggled&quot; zugewiesen, falls der Wert &quot;isToggled&quot; des Objektes &quot;data&quot; auf &quot;true&quot; steht.</p>
<p>Ein weiterer wichtiger Baustein, der direkt mit Angular daherkommt, ist &quot;<em>ngFor&quot;. Wie der Name schon vermuten l&#xE4;sst, handelt es sich hierbei um eine Art For-Schleife, mit der eine Komponente f&#xFC;r z.B. mehrere Elemente eines Arrays erzeugt werden kann. ngFor ist eine Strukturelle Directive und das wird mit einem vorangestellten &quot;</em>&quot; gekennzeichnet:</p>
<pre><code class="language-HTML">&lt;p *ngFor=&quot;let task of tasks&quot;&gt;
    {{task.name}}
&lt;/p&gt;
</code></pre>
<p>Hier w&#xFC;rde durch das Array &quot;tasks&quot; iteriert werden, und f&#xFC;r jeden Task ein p-Tag angelegt werden, in welchem der Name des Tasks ausgegeben wird.</p>
<p>Die n&#xE4;chste wichtige strukturelle Directive w&#xE4;re &quot;*ngIf&quot;. Auch hier ist der Name Programm. Mit &quot;*ngIf&quot; lassen sich gewisse Elemente in Abh&#xE4;ngigkeit zu einer Bedingung anzeigen, oder eben auch nicht.</p>
<pre><code class="language-HTML">&lt;p *ngIf=&quot;dummyBoolean&quot;&gt;
    {{task.name}}
&lt;/p&gt;
</code></pre>
<p>In diesem Fall wird der Paragraph also angezeigt wenn &quot;dummyBoolean&quot; den Wert &quot;true&quot; enth&#xE4;lt. Innerhalb der Anf&#xFC;hrungszeichen kann aber auch jede andere Expression stehen, solange diese am Ende entweder &quot;true&quot; oder &quot;false&quot; ergibt.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="services-a-nameservicea">Services <a name="service"></a></h2>
<p>Services werden strikt von Komponenten getrennt, um die Modularit&#xE4;t und Wiederverwendbarkeit des Codes zu verbessern. Durch diese Aufteilung werden die Komponenten um einiges aufger&#xE4;umter, da man die Funktionalit&#xE4;t die direkt mit der Ansicht zu tun hat, von anderen Prozessen &quot;im Hintergrund&quot; trennt. So kann eine Komponente dann spezielle Aufgaben an verschiedenste Services deligieren.</p>
<p>Services k&#xF6;nnen ebenfalls durch das CLI erstellt werden:</p>
<pre><code class="language-Bash">ng generate service &lt;service-name&gt;
</code></pre>
<p>Auch hier gilt: Optional kann ein Pfad zum Service (ausgehend vom Ordner &quot;src&quot;) angegeben werden, unter welchem dieser zu finden sein soll. Alle Unterordner zu diesem Pfad werden falls n&#xF6;tig automatisch erstellt.</p>
<p>Ein Service besteht aus einer TypeScript Datei, welche nach dem Schema &lt;name&gt;.service.ts benannt ist. Diese Datei sieht typischerweise so aus:</p>
<pre><code class="language-JavaScript">import { Injectable } from &apos;@angular/core&apos;;
    
@Injectable({
    provideIn:&apos;root&apos;
})    

export class DummyService {
    
    constructor() { }
    
    dummyMethod():string{
        return &quot;dummy&quot;;
    }
}
</code></pre>
<p>Dieser Service kann nat&#xFC;rlich erstmal nicht viel. Doch wie bindet man ihn jetzt ein?</p>
<pre><code class="language-JavaScript">import { Componentn} from &apos;@angular/core&apos;;
import {DummyService} from &apos;../../services/task.service&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./dummy.component.html&apos;,
    styleUrls:[&apos;./dummy.component.css&apos;]
})

export class Dummy implements OnInit{
    dummy_atribute:string;
    
    constructor(private dService: DummyService){}
    
    ngOnInit(): void{
        dummy_atribute = this.dService.dummyMethod();
    }
}
</code></pre>
<p>Hier passiert auf den ersten Blick sehr viel. Zuerst wird der Service importiert, um dann in die Komponente eingebunden zu werden. Das passiert als Parameter innerhalb des Konstruktors der Komponente. Von nun an exisitert in der &quot;Dummy&quot; Komponente eine Instanz vom DummyService mit dem Namen &quot;dService&quot;. Diese Instant wird in der &quot;onInit()&quot; Methode verwendet um eine Methode, welche der Service bereitstellt zu verwenden.</p>
<p>Ein sehr gutes und auch weit verbreitetes Beispiel f&#xFC;r einen Service, ist die Anbindung an ein Backend, um Daten von diesem zu beziehen, oder sie bereitzustellen. Im Abschnitt zum HTTP-Client wird so ein Service allgemein umschrieben.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="observables-a-nameobservablesa">Observables <a name="observables"></a></h2>
<p>Im Zusammenhang mit HTTP Requests l&#xE4;sst der Begriff &quot;Asynchrone Kommunikation&quot; nat&#xFC;rlich nicht lange auf sich warten. Angular soll ja Clientseitig weiter funktionieren w&#xE4;hrend es auf eine Antwort auf einen Request wartet. Hierf&#xFC;r stehen unter Angular sogenannte &quot;Observables&quot; bereit. Ein Observable ist quasi ein Objekt welches beobachtet (&quot;observed&quot;) werden kann, und R&#xFC;ckmeldungen weitergeben kann, sobald diese eintriffen. Angular verwendet hier die rxjs-Bibliothek. Wie genau das aussehen kann zeige ich am Beispiel des DummyServices:</p>
<pre><code class="language-JavaScript">import { Injectable } from &apos;@angular/core&apos;;
import {Observable, of} from &apos;rxjs&apos;;
    
@Injectable({
    provideIn:&apos;root&apos;
})    

export class DummyService {
    
    constructor() { }
    
    dummyMethod(): Observable&lt;string&gt;{
        const data = of(&quot;dummy&quot;);
        return data;
    }
}
</code></pre>
<p>Nun liefert die dummy-Methode ein Observable. Man spricht ab jetzt davon, dass man ein Observable &quot;abonniert&quot; sodass man es durchgehen &#xFC;berwachen kann. Das sieht in der Komponente so aus:</p>
<pre><code class="language-JavaScript">import { Componentn} from &apos;@angular/core&apos;;
import {DummyService} from &apos;../../services/task.service&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./dummy.component.html&apos;,
    styleUrls:[&apos;./dummy.component.css&apos;]
})

export class Dummy implements OnInit{
    dummy_atribute:string;
    
    constructor(private dService: DummyService){}
    
    ngOnInit(): void{
        this.dummyService.dummyMethod().subscribe(
            (data) =&gt; (this.dummy_atribute = data);
        );
    }
}
</code></pre>
<p>Man kann sich das abonnieren (subscribe) ein wenig so vorstellen wie ein &quot;Promise&quot; mit &quot;.then()&quot;. Innerhalb des Aufrufes der  &quot;subscribe&quot; Methode wird mit einer Arrow-Function angegeben, was mit den &#xFC;bergebenen Daten (hier &quot;data&quot;) passieren soll.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="subjects-und-subscriptions-a-namesubjectsa">Subjects und Subscriptions <a name="subjects"></a></h2>
<p>Eine andere Form von Observables sind Subjects. Ein Subject ist ein einzelnes Element, welches als Quell-Observable bezeichnet werden kann. Nun kann es ein oder mehrere Ziele geben, welches die Quelle durchgehend beobachten (eine/mehrere Subscription/s). Ein Subject wird h&#xE4;ufig in einem Service abgebildet:</p>
<pre><code class="language-JavaScript">import { Injectable } from &apos;@angular/core&apos;;
import {Observable, Subject} from &apos;rxjs&apos;;
    
@Injectable({
    provideIn:&apos;root&apos;
})    

export class SubjectService {
    private dummy_data: boolean = false;
    private subject = new Subject&lt;any&gt;();
    
    constructor() { }
    
    toggleDummyData():void {
        this.dummy_data = !this.dummy_data;
        this.subject.next(this.dummy_data);
    }
    
    onToggle(): Observable&lt;any&gt; {
        return this.subject.asObservable();
    }
}
</code></pre>
<p>Die Methode &quot;toggleDummyData&quot; im Beispiel, beschreibt eine Methode, die aufgerufen wird, sobald Daten ver&#xE4;ndert werden sollen. &quot;onToggle()&quot; w&#xE4;re die Methode die nun von mehreren Zielen abonniert werden kann, damit diese Ziele auf &#xC4;nderungen reagieren k&#xF6;nnen:</p>
<pre><code class="language-JavaScript">import { Componentn} from &apos;@angular/core&apos;;
import {SubjectService} from &apos;../../services/subject.service&apos;;
import {Subscription} from &apos;rxjs&apos;;

@Component({
    selector: &apos;app-button&apos;,
    templateUrl: &apos;./dummy.component.html&apos;,
    styleUrls:[&apos;./dummy.component.css&apos;]
})

export class Dummy implements OnInit{
    dummy_atribute:boolean;
    subscription: Subscription;
    
    constructor(private sService: SubjectService){
        this.subscription = this.sService.onToggle().subscribe(
            (value) =&gt; (this.dummy_attribute = value)
        );
    }
    
    ngOnInit(): void{
        
    }
    
    toggleDummy(){
        this.sService.toggleDummyData();
    }
}
</code></pre>
<p>In diesem Beispiel befinden sich der Ausl&#xF6;ser f&#xFC;r &#xC4;nderungen in den Daten, also die Methode &quot;toggleDummy()&quot; und die Reaktion auf die &#xC4;nderungen, also die Subscription, in der selben Komponente. Nun ist es essenziell zu verstehen, dass so eine Reaktion/Subscription von &#xFC;berall aus stattfinden kann. Man hat also eine Quelle und 1-n Empf&#xE4;nger, die auf die Quelle reagieren k&#xF6;nnen. Die eigentliche Subscription funktioniert prinzipiell wie ein einfacher aufruf eines Observables mittels &quot;.subscribe()&quot; und einer Arrow-Function als Parameter.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="http-client-a-namehttpa">HTTP Client <a name="http"></a></h2>
<p>Wie bereits erw&#xE4;hnt spielen Services und Observables vor allem in Zusammenhang mit HTTP-Requests eine Rolle. Angular kommt, in Kontrast zu anderen Frameworks, mit einem eingebauten HTTP-Client daher, welcher au&#xDF;erdem automatisch immer Daten vom Typ &quot;Observable&quot; zur&#xFC;ckgibt. Ich beschreibe das ganze hier weiter anhand des DummyServices und unter der Annahme, dass ein voll funktionsf&#xE4;higes Backend zur Verf&#xFC;gung steht. Zu Beginn ist es wichtig den Client in den Service zu importieren:</p>
<pre><code class="language-JavaScript">import { HttpClient, HttpHeaders } from &apos;@angular/common/http&apos;;
</code></pre>
<p>Doch damit das &#xFC;berhaupt funktionieren kann ist es noch n&#xF6;tig den Client als Modul zur Applikation hinzuzuf&#xFC;gen. Das ganze macht man, indem man in der Datei &quot;app.module.ts&quot; folgenden Import vornimmt:</p>
<pre><code class="language-JavaScript">import { HttpClientModule } from &apos;@angular/common/http&apos;;
</code></pre>
<p>Au&#xDF;erdem muss man das Modul noch zum &quot;imports&quot;-Array hinzuf&#xFC;gen:</p>
<pre><code class="language-JavaScript">imports:[
    BrowserModule,
    HttpClientModule
],
</code></pre>
<p>Nun folgt ein vollst&#xE4;ndiges Beispiel f&#xFC;r einen GET-Request an ein Backend innerhalb des DummyServices:</p>
<pre><code class="language-JavaScript">import { Injectable } from &apos;@angular/core&apos;;
import { HttpClient, HttpHeaders } from &apos;@angular/common/http&apos;;
import {Observable, of} from &apos;rxjs&apos;;
    
@Injectable({
    provideIn:&apos;root&apos;
})    

export class DummyService {
    private apiUrl = &apos;http://myBackend:5000/data&apos;;
    
    constructor(private http:HttpClient) { }
    
    dummyGET(): Observable&lt;string&gt;{
        return this.http.get&lt;string&gt;(this.apiUrl);
    }
}
</code></pre>
<p>&#xC4;hnlich wie bei einem eigens erstellten Service ist es hier n&#xF6;tig den Client in den Konstruktor einzubinden, um ihn dann verwenden zu k&#xF6;nnen. Der eigentliche GET-Request ist relativ selbsterkl&#xE4;rend. Interessanter wird es z.B. bei DELETE oder POST-Requests, da hier ggf. noch ID&apos;s und Header mit ins Spiel kommen. Dabei kommt es nat&#xFC;rlich ganz auf die Funktionalit&#xE4;t des Backends an. Hier also nochmal das Beispiel, aber diesmal mit einer Delete-Methode, welche die ID eines Datenelementes benn&#xF6;tigt, und mit einer Put- sowie Post-Methode, welche HTTP-Header verwenden:</p>
<pre><code class="language-JavaScript">import { Injectable } from &apos;@angular/core&apos;;
import { HttpClient, HttpHeaders } from &apos;@angular/common/http&apos;;
import {Observable, of} from &apos;rxjs&apos;;
    
const httpOptions = {
    headers: new HttpHeaders({
        &apos;Content-Type&apos;:&apos;appliction/json&apos;
    })
}
    
@Injectable({
    provideIn:&apos;root&apos;
})    

export class DummyService {
    private apiUrl = &apos;http://myBackend:5000/data&apos;;
    
    constructor(private http:HttpClient) { }
    
    dummyGET(): Observable&lt;string&gt;{
        return this.http.get&lt;string&gt;(this.apiUrl);
    }
    
    dummyDELETE(dummyData:data): Observable&lt;data&gt; {
        const url = `${this.apiUrl}/${data.id}`;
        return this.http.delete&lt;data&gt;(url);
    }
    
    dummyPUT(dummyData:data):Observable&lt;data&gt; {
         const url = `${this.apiUrl}/${data.id}`;
         return this.http.put&lt;data&gt;(url, data, httpOptions);
    }
    
    dummyPOST(dummyData:data):Observable&lt;data&gt; {
         return this.http.post&lt;data&gt;(this.apiUrl, task, httpOptions);
    }
}
</code></pre>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="forms-a-nameformsa">Forms <a name="forms"></a></h2>
<p>In fast jeder Applikation wird es wichtig sein, mit Web-Forms zu interagieren. Egal ob Textfeld, Radiobuttons, oder Dropdowns, User-Input wird so gut wie immer gefragt sein. Auch hier bietet Angular viele Funktionen, um den Umgang mit Forms m&#xF6;glichst angenehm zu gestalten. Schauen wir uns ein sehr einfaches Form an:</p>
<pre><code class="language-HTML">&lt;form&gt;
    &lt;div class=&quot;form-control&quot;&gt;
        &lt;label for=&quot;dummy&quot;&gt;Dummy Textbox&lt;/label&gt;
         &lt;input 
            type=&quot;text&quot; 
            name=&quot;dummy&quot; 
            id=&quot;dummy&quot;
        /&gt;
        &lt;input 
            type=&quot;submit&quot;
            value=&quot;submit&quot;
        /&gt;
    &lt;/div&gt;
&lt;/form&gt;
</code></pre>
<p>Wenn man jetzt ein Attribut der Komponente, in der dieses Form exisitert, mit einem Input-Feld des Forms beidseitig verkn&#xFC;pfen m&#xF6;chte (&quot;Two-way Databinding) bietet Angular hier das &quot;ngModel&quot;. Mit &quot;ngModel&quot; kann so ein &quot;Two-way Databinding&quot; erzielt werden. Ein Attribut der Komponente wird bidirektional mit einem Input-Element verkn&#xFC;pft. Daf&#xFC;r muss die Komponente nat&#xFC;rlich ein Attribut f&#xFC;r jedes Input-Element bereithalten. Um die Directive &quot;ngModel&quot; verwenden zu k&#xF6;nnen muss die Datei &quot;app.module.ts&quot; noch angepasst werden. Es muss, wie beim HttpClient, ein weiteres Modul zur Applikation hinzugef&#xFC;gt werden:</p>
<pre><code class="language-JavaScript">import { FormsModule } from &apos;@angular/forms&apos;;
</code></pre>
<p>Au&#xDF;erdem muss man das Modul noch zum &quot;imports&quot;-Array hinzuf&#xFC;gen:</p>
<pre><code class="language-JavaScript">imports:[
    BrowserModule,
    HttpClientModule,
    FormsModule
],
</code></pre>
<p>Innerhalb des HTML-Templates sieht die verwendung von &quot;ngModel&quot; wie folgt aus:</p>
<pre><code class="language-HTML">&lt;form&gt;
    &lt;div class=&quot;form-control&quot;&gt;
        &lt;label for=&quot;dummy&quot;&gt;Dummy Textbox&lt;/label&gt;
        &lt;input
            type=&quot;text&quot; 
            name=&quot;dummy&quot;
            [(ngModel)]=&quot;dummy_attribute&quot;
            id=&quot;dummy&quot;
        /&gt;
        &lt;input 
            type=&quot;submit&quot;
            value=&quot;submit&quot;
        /&gt;
    &lt;/div&gt;
&lt;/form&gt;
</code></pre>
<p>Mit Hilfe von ngModel (&quot;[()]&quot; = Input+Output) wird die Textbox &quot;dummy&quot; nun mit dem Attribut &quot;dummy_attribute&quot; verkn&#xFC;pft.</p>
<p>Auch f&#xFC;r das Abschicken von Forms (submit) bietet Angular seine eigene Funktionalit&#xE4;t.</p>
<pre><code class="language-HTML">&lt;form (ngSubmit)=&quot;onSubmit()&quot;&gt;
    &lt;div class=&quot;form-control&quot;&gt;
        &lt;label for=&quot;dummy&quot;&gt;Dummy Textbox&lt;/label&gt;
        &lt;input
            type=&quot;text&quot; 
            name=&quot;dummy&quot;
            [(ngModel)]=&quot;dummy_attribute&quot;
            id=&quot;dummy&quot;
        /&gt;
        &lt;input 
            type=&quot;submit&quot;
            value=&quot;submit&quot;
        /&gt;
    &lt;/div&gt;
&lt;/form&gt;
</code></pre>
<p>Mit dem Angular-Event &quot;ngSubmit&quot; kann das Abschicken des Forms abgefangen und mit einer Custom-Methode behandelt werden.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="routing-a-nameroutinga">Routing <a name="routing"></a></h2>
<p>Angular ist ein Framework f&#xFC;r &quot;Single-Page Applications&quot;. Das bedeutet nat&#xFC;rlich nicht, dass man mit Angular immer nur eine einzelne Seite eine Applikation bauen kann. Es bedeutet vielmehr, dass im Browser immer nur eine Seite ge&#xF6;ffnet bleibt, und das &quot;routing&quot; verschiedener Seiten quasi im Hintergrund unter Angular passiert. Prinzipiell wird erstmal die &quot;app-root&quot; Komponente geladen, und mit dieser dann alle Komponenten, welche in &quot;app-root&quot; verankert sind. Nun bietet Angular auch die Funktionalit&#xE4;t, verschiedene Komponenten unter verschiedenen URL&apos;s bereitzustellen. So k&#xF6;nnen unter &quot;myDomain.com/&quot; andere Komponenten geladen und angezeigt werden als unter &quot;myDomain.com/about&quot;. Hierf&#xFC;r verwendet man den Angular Router.</p>
<p>Den Router aktiviert man entweder beim erstellen einer neuen App, oder man aktiviert ihn sp&#xE4;ter manuell, indem man wieder eine kleine &#xC4;nderung an der Datei &quot;app.module.ts&quot; vornimmt:</p>
<pre><code class="language-JavaScript">import { RouterModule, Routes } from &apos;@angular/router&apos;;
</code></pre>
<p>Au&#xDF;erdem muss man das Modul noch zum &quot;imports&quot;-Array hinzuf&#xFC;gen:</p>
<pre><code class="language-JavaScript">imports:[
    BrowserModule,
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)
],
</code></pre>
<p>Nun kann man auch schon seine Routes erzeugen. Das ganze passiert ebenfalls in der &quot;app.module.ts&quot; Datei, &#xFC;berhalb des Decorators &quot;@NgModule&quot;. Hier einmal ein Beispiel f&#xFC;r verschiedene Routen:</p>
<pre><code class="language-JavaScript">const appRoutes: Routes = [
    {path: &apos;&apos;, component:DummyComponent},
    {path; &apos;about&apos;, component; AboutComponent}
]
</code></pre>
<p>Das ganze ist relativ selbsterkl&#xE4;rend. Man verkn&#xFC;pft einfach einen spezifischen Pfad mit einer gew&#xFC;nschten Komponente, welche dann unter diesem Pfad erreichbar ist. Damit Angular wei&#xDF;, wo genau der &quot;Output&quot; des Routers geladen und gerendert werden soll ist noch eine Modifikation an der Hauptkomponente, unter &quot;app.component.html&quot; n&#xF6;tig. Hier muss noch ein spezieller Tag eingef&#xFC;gt werden:</p>
<pre><code class="language-HTML">&lt;router-outlet&gt;&lt;/router-outlet&gt;
</code></pre>
<p>Jetzt werden in &quot;app-root&quot; immer die Komponenten, die zum derzeitigen Pfad passen, geladen und angezeigt.</p>
<!--kg-card-end: markdown--><p></p><!--kg-card-begin: markdown--><h2 id="weiterf%C3%BChrendes-material-a-namelinksa">Weiterf&#xFC;hrendes Material <a name="links"></a></h2>
<p>Ich hoffe ich konnte mit dieser knappen Einf&#xFC;hrung einigen Leuten weiterhelfen, oder zumindest Interesse erwecken. Vermutlich ist es am wichtigsten, die hier erkl&#xE4;rten Funktionen einfach mal selbst auszuprobieren, um sie richtig zu verstehen und sie mal vor Augen zu haben. Daf&#xFC;r m&#xF6;chte ich noch zwei Quellen verkn&#xFC;pfen, welche meiner Meinung nach den Umgang mit Angular sehr detailliert, aber auch verst&#xE4;ndlich erkl&#xE4;ren:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=3dHNOWTI7H8">Angular Crash Course 2021, Traversy Media</a></li>
<li><a href="https://www.tektutorialshub.com/angular-tutorial/">Complete Angular Tutorial For Beginners</a></li>
</ul>
<p>Vielen Dank f&#xFC;r&apos;s lesen!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>