Introduksjon til Akka HTTP

1. Oversikt

I denne opplæringen lærer vi, ved hjelp av Akkas Actor & Stream-modeller, hvordan du konfigurerer Akka for å lage et HTTP API som gir grunnleggende CRUD-operasjoner.

2. Maven-avhengigheter

For å starte, la oss se på avhengighetene som kreves for å begynne å jobbe med Akka HTTP:

 com.typesafe.akka akka-http_2.12 10.0.11 com.typesafe.akka akka-stream_2.12 2.5.11 com.typesafe.akka akka-http-jackson_2.12 10.0.11 com.typesafe.akka akka-http- testkit_2.12 10.0.11 test 

Vi kan selvfølgelig finne den nyeste versjonen av disse Akka-bibliotekene på Maven Central.

3. Opprette en skuespiller

Som et eksempel bygger vi et HTTP API som lar oss administrere brukerressurser. API-et vil støtte to operasjoner:

  • opprette en ny bruker
  • laster en eksisterende bruker

Før vi kan tilby et HTTP API, vi trenger å implementere en aktør som gir operasjonene vi trenger:

klasse UserActor utvider AbstractActor {private UserService userService = ny UserService (); statiske rekvisitter rekvisitter () {return Props.create (UserActor.class); } @Override public Receive createReceive () {return receiveBuilder () .match (CreateUserMessage.class, handleCreateUser ()) .match (GetUserMessage.class, handleGetUser ()) .build (); } privat FI.UnitApply handleCreateUser () {return createUserMessage -> {userService.createUser (createUserMessage.getUser ()); avsender (). fortell (ny ActionPerformed (String.format ("Bruker% s opprettet.", createUserMessage.getUser (). getName ())), getSelf ()); }; } privat FI.UnitApply handleGetUser () {return getUserMessage -> {sender (). fortell (userService.getUser (getUserMessage.getUserId ()), getSelf ()); }; }}

I utgangspunktet utvider vi AbstractActor klasse og implementere dens createReceive () metode.

Innenfor createReceive (), vi er kartlegge innkommende meldingstyper til metoder som håndterer meldinger av den respektive typen.

Meldingstypene er enkle containerklasser som kan serieiseres, med noen felt som beskriver en bestemt operasjon. GetUserMessage og har ett felt bruker-ID for å identifisere brukeren som skal lastes inn. CreateUserMessage inneholder en Bruker objekt med brukerdataene vi trenger for å opprette en ny bruker.

Senere får vi se hvordan vi kan oversette innkommende HTTP-forespørsler til disse meldingene.

Til slutt delegerer vi alle meldinger til a UserService forekomst, som gir den forretningslogikken som er nødvendig for å administrere vedvarende brukerobjekter.

Legg også merke til Rekvisitter() metode. Mens Rekvisitter() metoden er ikke nødvendig for å utvide AbstractActor, det vil komme godt med senere når du oppretter ActorSystem.

For en mer inngående diskusjon om skuespillere, ta en titt på vår introduksjon til Akka Actors.

4. Definere HTTP-ruter

Å ha en skuespiller som gjør selve jobben for oss, alt vi har igjen å gjøre er å tilby et HTTP API som delegerer innkommende HTTP-forespørsler til skuespilleren vår.

Akka bruker konseptet med ruter for å beskrive et HTTP API. For hver operasjon trenger vi en rute.

For å opprette en HTTP-server utvider vi rammeklassen HttpApp og implementere ruter metode:

klasse UserServer utvider HttpApp {private final ActorRef userActor; Timeout timeout = new Timeout (Duration.create (5, TimeUnit.SECONDS)); UserServer (ActorRef userActor) {this.userActor = userActor; } @Override offentlige ruteruter () {retursti ("brukere", dette :: postUser) .ellerElse (bane (segment ("brukere"). Skråstrek (longSegment ()), id -> rute (getUser (id)) )); } privat rute getUser (lang id) {retur get (() -> {CompletionStage user = PatternsCS.ask (userActor, new GetUserMessage (id), timeout) .thenApply (obj -> (Valgfritt) obj); return onSuccess (() -> bruker, utført -> {if (Performed.isPresent ()) Return Complete (StatusCodes.OK, Performed.get (), Jackson.marshaller ()); Ellers Return Complete (StatusCodes.NOT_FOUND); }); }); } privat rute postbruker () {retur rute (innlegg (() -> enhet (Jackson.unmarshaller (User.class), bruker -> {CompletionStage userCreated = PatternsCS.ask (userActor, ny CreateUserMessage (bruker), tidsavbrudd). deretter gjelder (obj -> (ActionPerformed) obj); return onSuccess (() -> userCreated, performed -> {return complete (StatusCodes.CREATED, performed, Jackson.marshaller ());});}))); }} 

Nå er det ganske mye kokeplate her, men merk at vi følger samme mønster som før kartleggingsoperasjoner, denne gangen som ruter. La oss bryte det litt ned.

Innenfor getUser (), pakker vi ganske enkelt innkommende bruker-ID i en type melding GetUserMessage og videresend den meldingen til vår userActor.

Når skuespilleren har behandlet meldingen, blir onSuccess handler kalles, der vi fullstendig HTTP-forespørselen ved å sende et svar med en viss HTTP-status og en viss JSON-kropp. Vi bruker Jackson marshaller for å serieisere svaret fra skuespilleren til en JSON-streng.

Innenfor postbruker (), vi gjør ting litt annerledes, siden vi forventer en JSON-kropp i HTTP-forespørselen. Vi bruker enhet () metode for å kartlegge den innkommende JSON-kroppen i en Bruker før du pakker den inn i en CreateUserMessage og videreformidle det til skuespilleren vår. Igjen bruker vi Jackson til å kartlegge mellom Java og JSON og omvendt.

Siden HttpApp forventer at vi skal tilby en singel Rute objekt, kombinerer vi begge rutene til en enkelt innenfor ruter metode. Her bruker vi sti direktivet for å endelig gi URL-banen der API-en vår skal være tilgjengelig.

Vi binder ruten som tilbys av postbruker () til stien / brukere. Hvis den innkommende forespørselen ikke er en POST-forespørsel, vil Akka automatisk gå inn i ellers gren og forventer at stien skal være / brukere / og HTTP-metoden skal være GET.

Hvis HTTP-metoden er GET, vil forespørselen bli videresendt til getUser () rute. Hvis brukeren ikke eksisterer, vil Akka returnere HTTP-status 404 (ikke funnet). Hvis metoden ikke er en POST eller en GET, vil Akka returnere HTTP-status 405 (Metoden er ikke tillatt).

For mer informasjon om hvordan du definerer HTTP-ruter med Akka, ta en titt på Akka-dokumentene.

5. Starte serveren

Når vi har opprettet en HttpApp implementering som ovenfor, kan vi starte HTTP-serveren vår med et par kodelinjer:

public static void main (String [] args) kaster Unntak {ActorSystem system = ActorSystem.create ("userServer"); ActorRef userActor = system.actorOf (UserActor.props (), "userActor"); UserServer server = ny UserServer (userActor); server.startServer ("localhost", 8080, system); }

Vi oppretter ganske enkelt en ActorSystem med en enkelt aktør av typen UserActor og start serveren på lokal vert.

6. Konklusjon

I denne artikkelen har vi lært om det grunnleggende om Akka HTTP med et eksempel som viser hvordan du konfigurerer en HTTP-server og eksponerer sluttpunkter for å opprette og laste ressurser, i likhet med et REST API.

Som vanlig kan kildekoden som presenteres her, bli funnet på GitHub.