Zum Hauptinhalt springen
Hilfecenter

API Compact Guide

Der vollständige projectfacts/teamspace API Compact Guide – komplett auf dieser Seite zum Lesen, mit allen Konzepten, Request-/Response-Beispielen und Cheat-Sheets, sowie als PDF und PowerPoint zum Herunterladen.

Der API Compact Guide ist die ausführliche Gesamtanleitung zur API – mit allen Konzepten und konkreten Request-/Response-Beispielen. Der komplette Inhalt der Präsentation steht hier auf dieser Seite; zusätzlich kannst du ihn als PDF, PowerPoint oder online ansehen.

Sprache & Server: Die Originalpräsentation ist in englischer Sprache verfasst und nennt projectfacts-Beispiel-Server (sync.projectfacts.de). Für teamspace gilt dieselbe API unter deiner eigenen Server-Adresse (z. B. https://app1.teamspace.de). Die Inhalte unten sind ins Deutsche übertragen; die Code- und JSON-Beispiele sind unverändert übernommen.

Herunterladen

projectfacts API Compact Guide — Version 0.36, benötigt projectfacts 6.00 oder neuer (Stand: 2021-03-09).

Überblick

Der Guide führt durch die folgenden Themen:

  1. Buzzwords – welche Standards und Best Practices verwendet werden.
  2. Autorisierung – was über die API gemacht werden kann.
  3. Authentifizierung – das Sicherheitskonzept der API mit seinen drei Wegen:
    • Login-Authentifizierung
    • Token-Authentifizierung
    • Interface-Authentifizierung
  4. Der projectfacts API-Explorer – das Werkzeug zum Erkunden der API.
  5. Durchgängiges Beispiel – die Adresse einer Organisation aktualisieren.
  6. Was zu beachten ist – Hinweise für die Praxis.

Buzzwords: Was du vorher kennen solltest

Bevor es losgeht, solltest du mit diesen Themen vertraut sein:

  • REST
  • JSON
  • HATEOAS
  • Basic Auth

Autorisierung: Was über die API möglich ist

Grundsätzlich hat ein API-Nutzer dieselben Rechte wie in der Weboberfläche (projectfacts/teamspace):

  • Wer in der Weboberfläche Projekte löschen darf, kann das auch über die API tun. Das lässt sich nicht verhindern.
  • Ebenso kannst du diesen Nutzer nicht daran hindern, eine eigene App zum Löschen von Projekten zu entwickeln: Du kannst einem Nutzer die Nutzung der API nicht grundsätzlich verbieten.
  • Wer in der Weboberfläche keine Zeiten buchen darf, kann das auch über die API nicht.

Ausnahme: Die Nutzung der API über projectfacts-Interfaces (Interface-Authentifizierung) folgt eigenen Regeln – dazu später mehr.

Authentifizierung: Das Sicherheitskonzept der API

Du kannst die API nicht einfach mit deinem projectfacts-Passwort verwenden. Würde man das Passwort bei jeder Anfrage mitschicken, entstünden mehrere Probleme:

  • Passwort bei jeder Anfrage übertragen? ➜ Risiko, dass es abgefangen wird. 😬
  • Ein Client wird kompromittiert? ➜ Passwort ändern ➜ alle Clients würden getrennt. 😞
  • Das Passwort müsste auf dem Client gespeichert werden. 😲

Deshalb gibt es drei eigene Authentifizierungswege.

Login-Authentifizierung

Die einzige Ressource, die du mit deinen projectfacts-Zugangsdaten (Login-Authentifizierung) ansprechen kannst, ist die device-Ressource (Gerät). Sie muss beim ersten Anmelden aus deiner App heraus angelegt werden:

POST https://sync.projectfacts.de/api/device/
{
  "email": "user@provider.com",
  "password": "projectfactsPassword",
  "deviceName": "YourAppName",
  "deviceType": "de.fivepoint.other"
}

Gibt es einen Nutzer mit passender E-Mail und passendem Passwort, antwortet der Server mit der neuen device-Ressource. Sie enthält die Device-ID und den API-Token, mit denen du alle folgenden Anfragen authentifizierst:

{
  "_id": "10001234",
  "token": "D1C2B3A4",
  "deviceName": "NameOfYourApp",
  [...]
}

Wichtig: Diese Daten muss deine App speichern – niemals das ursprüngliche projectfacts-Passwort! Den Token bekommst du nur dieses eine Mal.

Token-Authentifizierung

Alle regulären Anfragen werden per Basic Auth mit Device-ID und Device-Token abgesichert – sie repräsentieren sowohl den Nutzer deiner App als auch das verwendete Gerät.

So baust du den Authorization-Header in JavaScript auf:

// API-Request in Javascript
var credsB64 = window.btoa(device._id + ':' + device.token)
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Authorization', 'Basic ' + credsB64);
xhr.onload = function(response) { /*...*/ };
xhr.send();

Dabei liegt im lokalen Speicher deiner App:

{
  "_id": "10001234",
  "token": "D1C2B3A4",
  [...]
}

Die Berechtigung eines Geräts kann entzogen werden, indem das Gerät innerhalb von projectfacts gelöscht wird („Meine Geräte”). Andere Geräte/Apps sind davon nicht betroffen.

Interface-Authentifizierung

Für nicht-personenbezogene Apps, die nicht „im Namen” eines Nutzers handeln (z. B. ein Check-In/Out-Terminal):

  • Basic Auth mit Interface-ID und -Passwort.
  • Das Passwort wird in der projectfacts-Konfiguration (Interfaces) gesetzt.
  • Keine Nutzer-Berechtigungen – die Rechte ergeben sich aus den Einstellungen des Interfaces.
  • Eine Einschränkung der verbindenden IP-Adresse ist möglich.

Der projectfacts API-Explorer

Den API-Explorer erreichst du unter:

https://sync.projectfacts.de/htdocs/apps/apiexplorer/index.html

…oder unter der Wurzel deines pf-Servers + /htdocs/....

Es handelt sich um eine HTML5-/AngularJS-App, mit der du:

  • unsere API durchsuchst,
  • siehst, wie Ressourcen und Relationen dargestellt werden,
  • lernst, wie man Queries nutzt,
  • die Kommunikation über die Entwicklertools des Browsers verfolgst.

Die JSON-Repräsentationen als TypeScript-Klassen findest du unter:

https://sync.projectfacts.de/api/api/dto.ts

Schau dir das unbedingt einmal an!

Beispiel: Die Adresse einer Organisation aktualisieren

Wir suchen in unserer App nach „Example corp” und aktualisieren deren Adresse. Dazu sind folgende Schritte nötig:

  1. GET auf /api/contact inklusive Such-Query.
  2. GET auf die gewünschte contact-Ressource.
  3. GET auf die Hauptadresse des Kontakts.
  4. PUT auf diese Adresse.

Schritt 1 — Kontakt suchen

Wir suchen nach „Example corp.” (der Nutzer hat „examp” in unsere App getippt). Dazu führen wir ein GET mit Device-ID und Token als Basic-Auth-Header aus:

GET https://sync.projectfacts.de/api/contact?caption*=examp

Die Bestandteile der URL:

BestandteilBedeutung
contactZu durchsuchende Ressource (contact resource).
captionFeld, auf das gefiltert wird (Bezeichnung des Elements).
*=Operator „enthält” – im Gegensatz zu =ist gleich”.
exampSuchwert (der Operator = ist nicht case-sensitiv).

Ergebnis (Auszug):

{
 "size": 3, "offset": 0, "limit": 100,
 "items": [
  {"caption": "Max TexaMP", "href": "https://…/api/contact/1234", "value": 1234},
  {"caption": "Ben Examplename", "href": "https://…/api/contact/2345", "value": 2345},
  {"caption": "Example corp.", "href": "https://…/api/contact/3456", "value": 3456}
 ]
}

HATEOAS: Über das mitgelieferte href geht es hier weiter – du baust keine IDs selbst zusammen, sondern folgst dem Link.

Schritt 2 — Kontakt laden

Wir laden „Example corp.” (der Nutzer hat den dritten Treffer ausgewählt):

GET https://sync.projectfacts.de/api/contact/3456

Ergebnis (Auszug):

{
 "_id": 3456, "_idKey": "39", "_lastModifiedDate": "2015-11-19T10:44:26.000+0000",
 "active": true,
 "person": false,
 "caption": "Example corp.",
 "firstname": null,
 "lastname": "Example corp.",
 "description": "Address outdated\nMoved?",
 "mainAddress": {"caption": ";;Examplestreet 7;Examplecity;;122456;Deutschland",
                "href": "…/api/contactfield/173880993", "rel": "contactfield",
                "title": "preferred postal address",
                "value": 173880993, "idKey": "174"}
}

Dazu drei Beobachtungen:

  • Meta-Informationen beginnen mit einem Unterstrich (_id, _idKey, _lastModifiedDate).
  • Kontakte können Personen wie auch Organisationen sein ("person": false ⇒ Organisation).
  • Komplexe Daten erscheinen als Link-Objekt (wieder HATEOAS): Die mainAddress ist ein Verweis. Ihr caption dient als „Vorschau” der Ressource.

Schritt 3 — Adressfeld laden

Wir laden die contactfield-Ressource, die als mainAddress referenziert ist:

GET https://sync.projectfacts.de/api/contactfield/173880993

Ergebnis (Auszug):

{
 "_id": 173880993, "_idKey": "174",
 "value": ";;Examplestreet 7;Examplecity;;122456;Deutschland",
 "customlabel": null,
 "type": {"caption": "Address", "value": "ADR",
         "href": "https://ws-cp/api/enum/contactfieldtype/ADR",
         "optionsUrl": "…/api/enum/contactfieldtype"},
 "subtype": {"caption": "Work", "value": "WORK",
            "href": "…/api/enum/contactfieldsubtype/WORK",
            "optionsUrl": "https://ws-cp/api/enum/contactfieldsubtype"},
 "contact": {"href": "…/api/contact/3456", "title": "Contact",
            "value": 3456, "idKey": "39"}
}

Dazu:

  • Die Adresse liegt im vCard-Format vor, inklusive der Möglichkeit für ein eigenes Label (customlabel).
  • Der Typ des Kontaktfelds ist ADR – wie in vCard.
  • type und subtype sind wieder Link-Objekte, die auf die Details verweisen. Sie verlinken zugleich eine Sammlung möglicher Werte (optionsUrl).

Schritt 4 — Adresse speichern

Nachdem wir den Wert geändert haben, speichern wir die geänderte contactfield-Ressource per PUT:

PUT https://sync.projectfacts.de/api/contactfield/173880993

Request-Daten (Auszug):

{
 "_id": 173880993, "_idKey": "174",
 "value": ";;Saalbaustraße 27;Darmstadt;;64283;Deutschland",
 "customlabel": null,
 "type": {"caption": "Address", "value": "ADR",
         "href": "…/api/enum/contactfieldtype/ADR",
         "optionsUrl": "…/api/enum/contactfieldtype"},
 "subtype": {"caption": "Arbeit", "value": "WORK",
            "href": "…/api/enum/contactfieldsubtype/WORK",
            "optionsUrl": "…/api/enum/contactfieldsubtype"},
 "contact": {"href": "…/api/contact/28883816", "title": "Contact",
            "value": 28883816, "idKey": "39"}
}

Einfache Datentypen wie Strings (hier value) lassen sich problemlos ändern.

Wie aktualisiert man die Link-Objekte (z. B. subtype)? Nur der value zählt. Du musst also nicht das komplette Link-Objekt zurückschicken – es genügt, den value zu setzen:

{
 "_id": 173880993, "_idKey": "174",
 "value": ";;Saalbaustraße 27;Darmstadt;;64283;Deutschland",
 "customlabel": null,
 "type": {"caption": "Adresse", "value": "ADR",
         "href": "…/api/enum/contactfieldtype/ADR",
         "optionsUrl": "…/api/enum/contactfieldtype"},
 "subtype": "HOME",
 "contact": {"href": "…/api/contact/28883816", "title": "Contact",
            "value": 28883816, "idKey": "39"}
}

…so funktioniert es auch! Statt des vollständigen Link-Objekts für subtype reicht der reine Wert "HOME".

Was zu beachten ist

  • Unsere API unterstützt dich beim Caching – nutze es!
  • Das Erste, was eine App beim Start tun sollte, ist, ihre device-Ressource zu laden – so weißt du von Anfang an, ob der Token noch gültig ist.
  • Denke daran, den Token sicher in deiner App zu speichern.
  • Unsere API ist noch nicht vollständig, wird aber von Zeit zu Zeit um weitere Ressourcen erweitert.
  • Unser projectfacts-Chat ist ein weiteres Beispiel, umgesetzt in TypeScript.
  • Wenn du eine öffentliche App entwickeln möchtest, kontaktiere uns – wir unterstützen dich!

Cheat-Sheet: Query-Filter (Sammlungen)

Filter werden als Query-Parameter an eine Sammlungs-URL gehängt:

TypSyntaxBeispielBedeutung
Match (gleich)…?field=valuename="bob ross"&car=volvo&age=3Anführungszeichen nur bei Bedarf (nur Strings).
Contains (enthält)…?field*=valname*="bo"&car=volNamen, die „bo” enthalten.
Range (Bereich)…?field=1..3name="alice".."bob"&age=20..30Werte 20, 30 und dazwischen.
Or (oder)…?field=A,B,Cname=alice,"bob ross",charlieAlle Alices, Charlies und Bob Rosses.
Not empty (nicht leer)…?fieldname=bob&carBobs, die ein Auto besitzen.
Empty (leer)…?!fieldname=bob&!carBobs, die kein Auto besitzen.

Cheat-Sheet: Matrix-Parameter (Sammlungen)

Matrix-Parameter steuern Sortierung, Umfang und Auflösung einer Sammlung:

FunktionSyntaxBedeutung
Aufsteigend sortieren...;sort=name?...Elemente nach name aufsteigend sortieren.
Absteigend sortieren...;sort=!name?...Elemente nach name absteigend sortieren.
Ergebnisgröße...;limit=100?...Die ersten 100 Elemente nach dem Offset laden.
Ergebnis-Offset...;offset=200?...Die ersten 200 Elemente überspringen.
Teilbaum...;parent=1234?...Kinder von Element 1234 laden (nur Baumstrukturen).
Tiefe (evtl. LANGSAM!)…;depth=1?...Erste Generation von Referenzen auflösen (LANGSAM!).
Hinweise anzeigen…;showhints=true?...Verfügbare Sortierungen anzeigen (sort by xyz).

Cheat-Sheet: Matrix-Parameter (Elemente)

FunktionSyntaxBedeutung
7-Tage-Caching-Header…;lck=value?...Die Antwort wird mit einem 7-Tage-Caching-Header zurückgegeben.

„value" sollte eine Art Version der Ressource abbilden. Solange sie sich nicht ändert, verwendet dein HTTP-Client seinen Cache, statt die Ressource erneut vom Server zu laden.

Tipp: Verwende das "_lastModifiedDate" aus der Sammlungs-Ressource, um sicherzustellen, dass du ein frisches Element erhältst, wenn es auf dem Server geändert wurde.

Hinweise

  • Die lokalen Dateien (PDF/PowerPoint) sind eine Kopie des Stands zum Redaktionszeitpunkt. Die Online-Version kann aktueller sein.
  • Der Guide ist im Original in englischer Sprache verfasst und nennt projectfacts-Beispiel-Server (sync.projectfacts.de); für teamspace gilt dieselbe API unter deiner eigenen Server-Adresse.

Verwandte Themen