HATEOAS za proljetnu odmarališnu uslugu

OSTALO Vrh

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

1. Pregled

Ovaj će se članak usredotočiti na primjena mogućnosti otkrivanja u proljetnoj REST usluzi i na zadovoljavanju ograničenja HATEOAS-a.

Ovaj se članak usredotočuje na proljetni MVC. Naš članak Uvod u proljetni HATEOAS opisuje kako koristiti HATEOAS u Spring Boot-u.

2. Nevezanost otkrića kroz događaje

Otkrivenost kao zasebni aspekt ili briga web sloja treba odvojiti od kontrolera rukovanje HTTP zahtjevom. U tu svrhu upravljač će aktivirati događaje za sve radnje koje zahtijevaju dodatnu manipulaciju odgovorom.

Prvo, kreirajmo događaje:

javna klasa SingleResourceRetrieved proširuje ApplicationEvent {private HttpServletResponse odgovor; javni SingleResourceRetrieved (Izvor objekta, odgovor HttpServletResponse) {super (izvor); this.response = odgovor; } javni HttpServletResponse getResponse () {povratni odgovor; }} javna klasa ResourceCreated proširuje ApplicationEvent {private HttpServletResponse odgovor; private long idOfNewResource; javni ResourceCreated (izvor objekta, odgovor HttpServletResponse, long idOfNewResource) {super (izvor); this.response = odgovor; this.idOfNewResource = idOfNewResource; } javni HttpServletResponse getResponse () {povratni odgovor; } public long getIdOfNewResource () {return idOfNewResource; }}

Zatim, kontroler, s 2 jednostavne operacije - pronađi po id i stvoriti:

@RestController @RequestMapping (value = "/ foos") javna klasa FooController {@Autowired private ApplicationEventPublisher eventPublisher; @Autowired privatna usluga IFooService; @GetMapping (value = "foos / {id}") public Foo findById (@PathVariable ("id") Long id, HttpServletResponse response) {Foo resourceById = Preconditions.checkNotNull (service.findOne (id)); eventPublisher.publishEvent (novi SingleResourceRetrieved (ovaj, odgovor)); vratiti resourceById; } @PostMapping @ResponseStatus (HttpStatus.CREATED) stvaranje javne praznine (@RequestBody Foo resurs, HttpServletResponse odgovor) {Preconditions.checkNotNull (resurs); Long newId = service.create (resource) .getId (); eventPublisher.publishEvent (novi ResourceCreated (this, response, newId)); }}

Tada te događaje možemo obrađivati ​​s bilo kojim brojem nevezanih slušatelja. Svaki od njih može se usredotočiti na svoj vlastiti slučaj i pomoći u ispunjavanju ukupnih ograničenja HATEOAS-a.

Slušatelji bi trebali biti zadnji objekti u nizu poziva i nije im potreban izravni pristup; kao takvi nisu javni.

3. Učinkovitost otkrivanja URI-ja novostvorenog resursa

Kao što je raspravljeno u prethodnom postu na HATEOAS-u, operacija stvaranja novog resursa trebala bi vratiti URI tog resursa u Mjesto HTTP zaglavlje odgovora.

To ćemo riješiti pomoću slušatelja:

Klasa @Component ResourceCreatedDiscoverabilityListener implementira ApplicationListener {@Override public void onApplicationEvent (ResourceCreated resourceCreatedEvent) {Preconditions.checkNotNull (resourceCreatedEvent); HttpServletResponse odgovor = resourceCreatedEvent.getResponse (); long idOfNewResource = resourceCreatedEvent.getIdOfNewResource (); addLinkHeaderOnResourceCreation (odgovor, idOfNewResource); } void addLinkHeaderOnResourceCreation (HttpServletResponse response, long idOfNewResource) {URI uri = ServletUriComponentsBuilder.fromCurrentRequestUri (). putanja ("/ {idOfNewResource}"). buildAndExpand (idOfNewResource) .toUri (); response.setHeader ("Lokacija", uri.toASCIIString ()); }}

U ovom primjeru, koristimo ServletUriComponentsBuilder - što pomaže u korištenju trenutnog zahtjeva. Na ovaj način, ne trebamo ništa prolaziti i jednostavno možemo statički pristupiti tome.

Ako bi se API vratio ResponseEntity - mogli bismo koristiti i Mjesto podrška.

4. Dobivanje jedinstvenog resursa

Pri dohvatu jednog resursa, klijent bi trebao moći otkriti URI kako bi dobio sve resurse te vrste:

Klasa @Component SingleResourceRetrievedDiscoverabilityListener implementira ApplicationListener {@Override public void onApplicationEvent (SingleResourceRetrieved resourceRetrievedEvent) {Preconditions.checkNotNull (resourceRetrievedEvent); HttpServletResponse odgovor = resourceRetrievedEvent.getResponse (); addLinkHeaderOnSingleResourceRetrieval (zahtjev, odgovor); } void addLinkHeaderOnSingleResourceRetrieval (HttpServletResponse odgovor) {String requestURL = ServletUriComponentsBuilder.fromCurrentRequestUri (). build (). toUri (). toASCIIString (); int positionOfLastSlash = requestURL.lastIndexOf ("/"); Niz uriForResourceCreation = requestURL.substring (0, positionOfLastSlash); Niz linkHeaderValue = LinkUtil .createLinkHeader (uriForResourceCreation, "collection"); response.addHeader (LINK_HEADER, linkHeaderValue); }}

Imajte na umu da semantika veze veze koristi "kolekcija" tip relacije, naveden i korišten u nekoliko mikroformata, ali još nije standardiziran.

The Veza zaglavlje je jedno od najčešće korištenih HTTP zaglavljaradi otkrića. Uslužni program za stvaranje ovog zaglavlja dovoljno je jednostavan:

javna klasa LinkUtil {javni statički String createLinkHeader (String uri, String rel) {return "; rel = \" "+ rel +" \ ""; }}

5. Otkrivenost u korijenu

Korijen je ulazna točka u cjelokupnoj usluzi - to je ono s čim klijent dolazi u kontakt prilikom prve upotrebe API-ja.

Ako se ograničenje HATEOAS treba razmatrati i provoditi cijelo vrijeme, tada je to mjesto za početak. Stoga svi glavni URI-ji sustava moraju se otkriti iz korijena.

Pogledajmo sada kontroler za ovo:

@GetMapping ("/") @ResponseStatus (value = HttpStatus.NO_CONTENT) public void adminRoot (konačni zahtjev HttpServletRequest, konačni odgovor HttpServletResponse) {String rootUri = request.getRequestURL (). ToString (); URI fooUri = novi UriTemplate ("{rootUri} {resurs}"). Expand (rootUri, "foos"); Niz linkToFoos = LinkUtil.createLinkHeader (fooUri.toASCIIString (), "collection"); response.addHeader ("Link", linkToFoos); }

Ovo je, naravno, ilustracija koncepta, usredotočujući se na jedan, uzorak URI-ja za Foo Resursi. Prava bi implementacija trebala dodati, slično, URI-je za sve resurse objavljene klijentu.

5.1. Otkrivenost nije promjena URI-ja

To može biti kontroverzna stvar - s jedne strane, svrha HATEOAS-a je da klijent otkrije URI-je API-ja i ne oslanja se na kodirane vrijednosti. S druge strane - web ne funkcionira na takav način: da, URI se otkrivaju, ali su i označeni.

Suptilna, ali važna razlika je evolucija API-ja - stari URI-i i dalje bi trebali raditi, ali svaki klijent koji će otkriti API trebao bi otkriti nove URI-je - što omogućuje API-ju da se dinamički mijenja i dobrim klijentima da rade dobro čak i kad API promjene.

U zaključku - samo zato što bi se svi URI-ji RESTful web usluge trebali smatrati cool URI-ima (a cool URI-i se ne mijenjaju) - to ne znači da pridržavanje ograničenja HATEOAS nije izuzetno korisno pri razvoju API-ja.

6. Upozorenja za otkrivanje

Kao što navode neke od rasprava oko prethodnih članaka, prvi je cilj otkrivanja minimalna ili nikakva upotreba dokumentacije i neka klijent nauči i shvati kako koristiti API putem odgovora koje dobije.

Zapravo, ovo se ne bi trebalo smatrati tako dalekim idealom - to je način na koji trošimo svaku novu web stranicu - bez ikakve dokumentacije. Dakle, ako je koncept problematičniji u kontekstu REST-a, onda se mora raditi o tehničkoj provedbi, a ne o tome je li to moguće ili ne.

To je rečeno, tehnički, još uvijek smo daleko od potpuno funkcionalnog rješenja - specifikacija i podrška za okvir i dalje se razvijaju, i zbog toga moramo napraviti neke kompromise.

7. Zaključak

Ovaj je članak obuhvatio provedbu nekih svojstava otkrivanja u kontekstu RESTful usluge s Spring MVC i dotaknuo se koncepta otkrivenosti u korijenu.

Provedbu svih ovih primjera i isječaka koda možete pronaći na GitHubu - ovo je projekt zasnovan na Mavenu, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.

OSTALO dno

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

$config[zx-auto] not found$config[zx-overlay] not found