Gatsby Webhook Service
Vor einiger Zeit hatte ich schon einmal darüber geschrieben wie man ein Webhook Service entwickeln kann. Meinen Qualitätsansprüchen konnte der aber nie wirklich erfüllen und da ich für ein Projekt etwas anständiges brauchte, nehme ich das zum Anlass einen aktualisierten Beitrag dazu zu verfassen.
Neben dem Triggern von gatsby build
, gatsby clean
und einer Kombination aus beidem, wird der Service auch Daten eines Instagram Feeds beziehen und bereitstellen. Wozu wird weiter unten erläutert. Die Requests zu Instagram werden mit dem Native Node HTTPS Modul gesendet. Um einen kleinen REST Service zu realisieren greife ich auf Fastify zurück. Ich habe während meiner Arbeit sehr gute Erfahrungen damit machen können und mir persönlich sagt es eher zu als Express. Letztendlich ist die Wahl hierbei gar nicht so entscheidend, da ich von einem moderaten Traffic aufkommen rechne. Zur Authentifizierung setze ich auf JWT.
Als Cache Store möchte ich einen Redis Server nutzen. Eine einfache Map würde es wohl auch tuen. Ich möchte allerdings den Server im Cluster auf allen CPU Kernen laufen lassen. Alternativ könnte man auch ein Fastify Plugin benutzen oder schreiben. Diese können bei der Fastify Instanz registriert werden und somit hat man dann auch im privaten Speicherbereich des jeweiligen Childs Zugriff darauf. Mein Ansatz bietet den Vorteil das der Cache auch beim Neustart des Servers erhalten bleibt. Was Vorteilhaft sein dürfte während der Entwicklung und dem Versuch dabei die Requests an Instagram in Grenzen zuhalten.
Das ganze soll in einer containersierten Umgebung à la Docker laufen.
Der Instagram Feed
Wie ich vor kurzem feststellen konnte gab es vor einiger Zeit diverse Plugins für ein beliebtes Blogger CMS, die ohne Access Token den persönlichen (oder auch jeden anderen) Instagram Feed abgreifen konnten.
Dazu war nur der Instagram Profilname nötig. Seit einiger Zeit funktioniert von diesen Plugins nur leider keins mehr. Da allerdings bei meinen aktuellen Projekt der Wunsch nach dem Feed bestand, suchte ich nach einer Methode den Feed ohne großen Aufwand abfragen zu können. Also erstellte ich mir ein Instagram Account - Ja. Ich hatte keinen. Ich kann mit Social Media einfach nichts anfangen. - und schaute mir als erstes die API an. Nach ein wenig Recherche fand ich dann doch den Endpoint, der das Profil im JSON Format per GET Request zum Client sendet. Er lautet https://www.instagram.com/[username]/?__a=1 und gehört scheinbar nicht zur OpenGraph API. Ich vermute das er für den Datenabruf per App gedacht ist aber um das genau zu sagen müsste ich den Traffic der Instagram App unter die Lupe nehmen und so interessant ist dann auch nicht.
Was mich stutzig machte war das der Server scheinbar auf Anfragen aus meinem Browser mit 200 und auf Anfragen von meinem Server aus mit 401 antwortete. Demnach muss man schlicht eingeloggt sein um Zugriff zu erhalten. Also kopierte ich alle Cookies die Instagram gesetzt hatte und fügte die dem Request Header der Anfrage von meinen Server hinzu und schon durfte er die angefragten Daten erhalten.
Funktionsweise
Also die Daten bekomme ich nun wenigsten schonmal, wenn ich ganz nett frage. Jetzt müssen diese noch aufbereitet und weitergeleitet werden. Damit Instagram nicht irgendwann auf die Idee kommt die IP meines Servers zu blockieren, wäre ein Cache auch äußerst praktisch.
Da sich Instagram bei den Bildern genauso zickig verhält müssen diese auch vom Server erst angefragt und dann ausgeliefert werden. Ich brauche diese allerdings nicht in der gelieferten Auflösung und Qualität. Von daher soll bei einer Anfrage nach einem Bild prüfen ob er dieses vorrätig hat. Wenn ja soll er es zum Client streamen. Andernfalls lädt er es vom Instagram CDN.
Mit dem Daten - Stream passiert nun folgendes: Es wird auf 640 * 640 Pixel runterskaliert und die Qualität wird ein wenig reduziert. Der Stream wird geklont. Einer wird in eine Datei auf dem lokalen Datenträger geschrieben und der andere wird in dem HTTP Socket gepiped. Quasi noch beim Download des Bildes wird es skaliert, optimiert, gesendet und ganz nebenbei auch noch gespeichert. Bei der nächsten Anfrage wird dann einfach das Bild von der Festplatte gesendet.
In meinem speziellen Anwendungsfall ist der gesamte Vorgang urheberrechtlich unproblematisch, da die Bilder auf dem Blog der Urheberin genutzt werden sollen.
Im nächsten Teil werde ich erläutern wie man den Container erstellt und werde neben dem Fastify Boilerplate Code mich um die ersten Gatsby Routen bemühen.