Workflow REST API-n

Bár kétségtelenül a REST a legelterjedtebb kommunikációs mód, akár ugyanolyan platformon fejlesztett alkalmazások között is, REST API tervezéskor nekem sok kérdés merül fel, melyre nem kapok megnyugtató választ, és sok olyan megoldással találkozom, amelyek nem felelnek meg a REST elveknek, vagy egyszerűen csak nem tetszenek.

Sokáig próbáltam megfogalmazni, hogy mi az alapvető problémám, és talán most sikerült közelebb kerülni. Vegyünk két microservice-t, melyek mindegyike Javaban készült, Spring Boot használatával. Mindkét oldalon a programozási nyelv alapeleme az osztályok, ahol érvényesül az egységbezárás, azaz az attribútumok mellett ott vannak a metódusok, a megfelelő paraméterekkel és visszatérési értékekkel. Ez a legtöbb fejlesztőnek triviális.

A REST a kettő között viszont egy teljesen más absztrakció, erőforrásokkal, és az azon végzett CRUD műveletekkel. Ez főleg négy műveletet takar, amit a GET, POST, PUT és DELETE HTTP metódusoknak feleltetünk meg. Egy objektum létrehozására tipikusan konstruktort használunk, ebből nem feltétlen egy van. Ezen kívül egy objektumnak lehet több metódusa, amik nem feltétlenül feleltethetőek meg a HTTP metódusoknak, hiszen nem csak ezeket az alapműveleteket használjuk, valamint lehet belőle sokkal több is, mint négy. Míg a Java nyelv szabvány, addig a REST csak egy ajánlás, és az sincs megfelelően definiálva, hogy hogyan kéne implementálni, az meg aztán pláne nincs, hogy a kettőt hogyan feleltessük meg egymásnak. És ennek az az eredménye, hogy minden projekten teljesen más megoldásokat látok, a legtöbb helyen kompromisszumokkal.

Absztrakciók

Az RPC alapú kommunikáció esetén igazából nincs ilyen probléma, mert nem szükséges átfordítás, nincs szükség az absztrakció váltására. Hiszen ott is eljárások vannak, paraméterekkel és visszatérési értékekkel. A Spring Frameworkben volt is ilyen lehetőség, hogy egy távoli eljáráshívás történt, azonban a protokollt kódolás nélkül cserélni lehetett alatta, pl. választhattunk RMI-t, vagy ki emlékszik még a Hessian és Burlap protokollokra. Sajnos ez azóta eltűnt. A SOAP esetén sem volt akkora probléma az átfordítás, hiszen ott is vannak az operációk (eljárásnak felel meg), és a paraméter, valamint a visszatérési érték is egy-egy (XML) dokumentum. Vannak modernebb RPC alapú kommunikációs protokollok is, mint pl. JSON-RPC, vagy az egyre inkább elterjedő multiplatform gRPC, bináris Protocol Buffers formátummal.

Amennyiben CRUD alkalmazásról van szó, a REST használata talán triviális. De ha egy olyan alkalmazásról beszélünk, amiben komoly üzleti logika van (és hiszem, hogy a legtöbb alkalmazásnak ilyennek kéne lennie, csak a fejlesztők “butítják le” CRUD alkalmazássá, amely végső soron oda is vezethet, hogy borzasztó felhasználói felületek kerülnek kifejlesztésre), akkor már több kérdés merül fel.

Vegyünk például egy hibajegykezelő alkalmazást (issue tracker), mely rendelkezzen egy minimális üzleti logikával. Ha hibajegy kerül felvételre, az új (new) állapottal kerül létrehozásra. Amennyiben valaki elkezd rajta dolgozni, átkerül folyamatban (in_progress) állapotba. Amennyiben elkészült, átkerül megoldott (resolved) állapotba. Bár a legtöbb hibajegykezelő alkalmazás lehetővé teszi, hogy egyedi munkafolyamatot lehessen benne létrehozni, ettől most tekintsünk el, mert akkor megint más problémák merülnek fel. Ezt egy egyszerű állapotdiagrammal lehet a legegyszerűbben szemléltetni.

Absztrakciók

Talán egy hibajegy felvételét még el tudom képzelni REST API-n (bár már ott is vannak kérdéseim), azonban a különböző munkafolyamat lépések implementálásakor már bizonytalanabb vagyok. Ez a poszt ezt a problémakört járja körbe, forráskódokkal alátámasztva.

Hőmérséklet monitorozása

Nagyon régóta érdekel az IoT (Internet of Things, azaz Internetre köthető kütyük) világa, ugyanis ezek azok az eszközök, melyek összekötik a virtuális világót a való világgal. Már régóta rendelkezem egy Raspberry PI számítógéppel, melyet azóta is lelkesen használok egy alacsony fogyasztású home serverként. Telepítve van rá a Prometheus és Grafana, mely a DevOps világban egy kvázi standard monitorozó eszköz. Mindkettő ingyenesen használható, nyílt forráskódú eszköz. A Prometheus különösen alkalmas idősorok hatékony tárolására, gyors lekérdezésére, aggregált műveletek végrehajtására. Az idősorok olyan megfigyelések, melyeket egymást követő időpontokban (időszakokban) regisztrálták, és ez az időbeliség az adatok fontos tulajdonsága. Ilyen például egy szerverrel kapcsolatban a bizonyos időpontokban lekérdezett CPU és memóriahasználat, vagy a háttértárakon lévő szabad hely mérete. A Grafana használatával ezeket tudjuk vizualizálni, gyönyörű dashboardokat létrehozni és akár riasztásokat beállítani.

De melyik is lehet az az IoT eszköz, melyet a legegyszerűbben, lehetőleg barkácsolás nélkül és olcsón lehetne bekötni ebbe a rendszerbe? Már régóta szemezem a Xiaomi Mi Temperature and Humidity Monitor 2 hőmérséklet-, és páratartalom mérővel, amihez most 2000 Ft-ért lehet hozzájutni az mStore akciója keretében.

Xiaomi Mi Temperature and Humidity Monitor 2

Ez pontosan a LYWSD03MMC modell, mely egy precíz Sensirion szenzorral, 1,5”-os LCD kijelzővel rendelkezik, és Bluetooth 4.2 BLE vezeték nélküli kapcsolaton keresztül kommunikál. Egy CR2032 elemmel működik, ezt külön szerezzük be, mert nem része a csomagnak. Ezzel akár fél-egy évig képes üzemelni. Természetesen Bluetooth-on tud kapcsolódni mobiltelefonhoz, illetve Bluetooth Gateway-hez, azonban én direktbe, egy Linuxos számítógéppel, jelen esetben egy Raspberry PI-vel szeretnék hozzá kapcsolódni, és kinyerni belőle az adatokat. (Nincs szükség egyedi firmware telepítésére.)

Ezt utána csak be kell kötni a Prometheusba, mely időközönként lekérdezi és eltárolja az adatokat, majd egy Grafana dashboardot létrehozni, mely megjeleníti azokat.

Grafana dashboard

Közben természetesen szerettem volna megismerni a kapcsolódó technológiákat is.

JTechLog Technology Radar

Emlékszem régebben mennyire nagy esemény volt mindig, mikor kijött a Thoughtworks Technology Radar legfrissebb kiadása. A Thoughtworksről annyit kell tudni, hogy 1999-ben csatlakozott a céghez Martin Fowler, és több munkatársával együtt jelentős és meghatározó könyveket írtak, melyeket én is javaslok elolvasni. Ezek például:

  • Martin Fowler - Refactoring
  • Martin Fowler - Patterns of Enterprise Application Architecture
  • Jez Humble, David Farley - Continuous Delivery
  • Sam Newman - Building Microservices

A cég mindig nagyon haladó gondolkodású volt, és bizonyos időközönként közreadta a Technology Radart, melyben grafikusan ábrázolták, hogy mi is a véleményük az épp aktuális technológiákról, eszközökről, módszertanokról.

Gondolatok a modell osztályokról, entitásokról, DTO-król

Nagyon szeretem azokat az írásokat, melyek különböző területekről származó fogalmakat próbálnak valamilyen egységes rendszerbe foglalni, a fogalmaknak egységes elnevezést adni. Ilyen volt a Tom Hombergs - Get Your Hands Dirty on Clean Architecture (2nd edition) könyv, mely a modell osztályokkal próbálta ezt tenni. Különösen tetszett, hogy nem egy megoldást fogad el igaznak, hanem ismerteti a különböző megoldásokat, összehasonlítva azok előnyeit és hátrányait.

A mostanában fejlesztett alkalmazások vagy a klasszikus háromrétegű (3-layer) architektúrával készülnek, vagy a modernebb Hexagonal vagy Clean Architecture-t használják.

Egy klasszikus Spring Boot alkalmazás esetén a három réteg a repository, service, controller. Java EE esetén ez a web, üzleti és EIS (Enterprise Information System) rétegek. Én egységesen úgy fogok rájuk hivatkozni, hogy prezentációs, üzleti logika és perzisztens réteg.

Clean Architecture esetén is megjelennek ezek, az alapvető különbség a függőségek irányában van, hiszen amíg a klasszikus háromrétegű alkalmazás esetén az üzleti logika réteg függ a perzisztens rétegtől, addig a Clean Architecture esetén a perzisztens réteg függ az üzleti logika rétegtől.

Minden rétegben szükség van azonban az adatokat tároló osztályokra, nevezzük ezeket modell osztályoknak. Manapság ezek egyszerű POJO (Plain Old Java Object) osztályok, pár attribútummal, konstruktorokkal, getter/setter metódusokkal.

Kérdés, hogy ebbe a fogalomrendszerbe hogyan illeszkednek be az entitások, DTO-k, stb.? Melyik rétegben helyezkednek el? Illetve kell-e, és hogyan kell ezek között a megfeleltetést elvégezni (mapping), konvertálni? Ez a poszt ebben próbál egyfajta rendet tenni.

Spring Security és Spring Boot

Technológiák: Spring Security 6, Spring Boot 3, Thymeleaf, Spring Data JPA, H2

(Azért írtam meg ezt a posztot, mert sokan kerestek a Spring Security-re, továbbá 2022 novemberében kijött a Spring Security 6 és Spring Boot 3, valamint teljesértékű Spring Security poszt Spring Boottal eddig hiányzott. A Spring Security használata Springgel Frameworkkel poszt továbbra is elérhető.)

A Spring Security egy olyan keretrendszer, mely támogatja az autentikációt, autorizációt és védelmet biztosít bizonyos támadási formák ellen. A Spring Security a de-facto szabványos eszköz a biztonság megvalósítására Springes alkalmazásokon belül.

A Spring Security támogatja a felhasználónév és jelszó párossal történő bejelentkezést, de ezen kívül pl. webszolgáltatások védelmére támogatja a HTTP BASIC, HTTP Digest és tanúsítvány alapú bejelentkezést, sőt az OAuth 2.0 használatát is.

A felhasználók és a hozzá kapcsolódó szerepkörök tárolhatóak memóriában, adatbázisban, LDAP szerveren, stb. Ezekhez adottak beépített implementációk, de saját is készíthető. Támogatja a jelszó hashelését különböző algoritmusokkal. A felhasználóval kapcsolatos információkat képes cache-elni is. Különböző eseményekre eseménykezelőket lehet aggatni, pl. bejelentkezés, így könnyen megoldható pl. audit naplózás.

Az alkalmazáson belül szerepkörökhöz lehet kötni bizonyos url-eket, valamint metódus szinten is meg lehet adni, hogy milyen szerepkörrel rendelkező felhasználó hívhatja meg.

A poszthoz egy példa projekt is tartozik, mely elérhető a GitHub-on. Egyszerű Spring Boot webes alkalmazás, Spring Data JPA perzisztens réteggel, Thymeleaf template engine-nel.