|
|
|
Auf dieser Seite geht es um den `src/db Ordner mitsamt dessen Kinder. Falls du wissen möchtest, wie du die API startest und konfigurierst schau dir die [Installationsanleitung](/de//Installation) und [Docker Seite](Docker) an.
|
|
|
|
|
|
|
|
[TOC]
|
|
|
|
|
|
|
|
## Datenbank
|
|
|
|
|
|
|
|
### questions.json
|
|
|
|
|
|
|
|
Diese Datei wurde genutzt um aus den Fragen SQL Abfragen zu generieren und existiert jetzt nur noch um eine menschenfreundlichere Alternative als die SQL Datei zum Überblick über Fragen zu bieten.
|
|
|
|
|
|
|
|
### schema.sql
|
|
|
|
|
|
|
|
Das Datenbankschema hat alle Definitionen, wie Tabellen erstellt werden sollen, fügt aber auch schon alle definierten Fragen ein. Falls weitere Tabellen erstellt werden sollen, können die SQL Befehle dafür in diese Datei gepackt werden. Falls neue Fragen abgedeckt werden sollen, können sie zu dem `INSERT INTO "question"` Statement hinzugefügt werden. Dafür sollte erst eine UUID generiert werden:
|
|
|
|
|
|
|
|
```sql
|
|
|
|
psql -U postgres
|
|
|
|
|
|
|
|
SELECT gen_random_uuid();
|
|
|
|
```
|
|
|
|
|
|
|
|
## API
|
|
|
|
|
|
|
|
Hier is die ganze Logik für die API, welche auf NodeJS und dem [express package](https://expressjs.com) läuft. Um das erstellen der Endpunkte zu vereinfachen und um den [OpenAPI Standard](https://swagger.io/specification/) zu befolgen, wurde außerdem das package [express-openapi](https://www.npmjs.com/package/express-openapi) genutzt, welches die API basierend auf der Dateistruktur erstellt.
|
|
|
|
|
|
|
|
### api-doc.js
|
|
|
|
|
|
|
|
Hier wird eine OpenAPI kompatible spezification erstellt, welche Informationen über die API bereitstellt. Mit dem `definitions` Schlüssel können Models, welche als in- und output fungieren, definiert werden. Wie man diese Definitionen erstellt kann in der [OpenAPI Dokumentation](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#schema) gefunden werden.
|
|
|
|
|
|
|
|
Falls typen etwas dynamischer sein sollen, können sie in der `open-api-types.js` Datei hinzugefügt werden und wo nötig mit weiteren Attributen folgendermaßen erweitert werden:
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
Model: {
|
|
|
|
type: "object",
|
|
|
|
properties: {
|
|
|
|
id: {
|
|
|
|
type: "string"
|
|
|
|
},
|
|
|
|
...typ_zum_erweitern
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Auf diese Weise können doppelte Definitionen verhindert werden
|
|
|
|
|
|
|
|
### Defining endpoints
|
|
|
|
|
|
|
|
`express-openapi` generiert die Endpunkte basierend auf die Ordnerstruktur in `paths`. Dabei wird ein Endpoint aus seinem Pfad zusammengesetzt. Eine solche Struktur
|
|
|
|
|
|
|
|
```shell
|
|
|
|
└── give
|
|
|
|
└── me
|
|
|
|
└── examples.js
|
|
|
|
```
|
|
|
|
|
|
|
|
generiert den Endpunkt `give/me/examples`.
|
|
|
|
|
|
|
|
Um parametrisierte Endpunkte, wie `give/me/example/id1` zu generieren, muss der Parameter einfach in geschweifte Klammern gepackt werden. Um also beim Endpunkt eine dynamische id angeben zu können, muss die Dateistruktur so aussehen:
|
|
|
|
|
|
|
|
```shell
|
|
|
|
└── give
|
|
|
|
└── me
|
|
|
|
└── examples
|
|
|
|
└── {id}.js
|
|
|
|
```
|
|
|
|
|
|
|
|
Die JavaScript Dateien beinhalten hierbei die Logik des Endpunktes. Hier kann definiert werden, welche HTTP Anfragen akzeptiert werden, wie der Input aussieht und was zurückgegeben wird. Ein beispiel Endpunkt, der GET Anfragen für den obrigen Pfad akzeptiert würde so aussehen:
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
export default function() {
|
|
|
|
//Akzeptierte Anfragen
|
|
|
|
let operations = {
|
|
|
|
GET
|
|
|
|
};
|
|
|
|
|
|
|
|
// req ist die Anfrage, res die Antwort und _next erlaubt Middleware
|
|
|
|
function GET(req, res, _next) {
|
|
|
|
//Gibt den 200 Status Code und die ID zurück
|
|
|
|
res.status(200).send(`You send {req.params.id}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dokumentation
|
|
|
|
GET.apiDoc = {
|
|
|
|
summary: "Gibt deine ID zurück",
|
|
|
|
// Input
|
|
|
|
parameters: [
|
|
|
|
{
|
|
|
|
in: "path",
|
|
|
|
name: "id",
|
|
|
|
type: "number",
|
|
|
|
description: "Die ID"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
// Hier werden alle möglichen Status Codes definiert
|
|
|
|
responses: {
|
|
|
|
200: {
|
|
|
|
description: "Sendet dir deine ID",
|
|
|
|
//Rückgabetyp
|
|
|
|
schema: {
|
|
|
|
type: "string"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Um einen Endpunkt zu erstellen, muss also diese nur entlang seines Pfades die Ordner aufgebaut werden und das package übernimmt den Rest.
|
|
|
|
|
|
|
|
### Services
|
|
|
|
|
|
|
|
Die meisten JavaScript Dateien an den Endpunkten verweisen auf einen Service im `services` Ordner. Damit wird die gesamte Logik des Endpunktes auf den Service verlagert. Meistes werden Services nach ihrer Aufgabe gruppiert, z.B. `questionsService.js` kümmert sich um alle Aufgaben, die mit Fragen zu tun haben. Um neue Funktionen hinzuzufügen kann ein bestehender Service einfach erweiter werden oder eine neue Datei erstellt werden, die aber dann in `index.js` importiert und zu den dependencies in `initialize` hinzugefügt werden muss.
|
|
|
|
|
|
|
|
### postgres.js
|
|
|
|
|
|
|
|
Diese Datei kommuniziert ausschließlich mit der Datenbank. Fast alle Services rufen Funktionen aus dieser Datei auf umd Ergebnisse aus der Datenbank zu bekommen. Diese Funktionen abstrahieren eigentlich nur SQL Abfragen an die Datenbank. Um eigene Abfragen hinzuzufügen, kann eine neue Funktion erstellt werden, die mit `client.query("abfrage")` die Datenbank anfragt. Sollte diese Abfrage dynamische Parameter haben, können diese nicht einfach in den String eingearbeitet, sondern lieber so erstellt werden:
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
client.query("SELECT from table WHERE id = $1 AND name = $2", [id, name])
|
|
|
|
```
|
|
|
|
|
|
|
|
So werden die Eingaben bereinigt um SQL Injections zu verhinder. Die Zahl vorm Dollarzeichen ($) ist der Index des Objektes in der Liste, was an der Stelle eingefügt wird. |