Introduktion til Akka HTTP

1. Oversigt

I denne vejledning lærer vi ved hjælp af Akkas Actor & Stream-modeller, hvordan man opsætter Akka til at oprette en HTTP API, der giver grundlæggende CRUD-operationer.

2. Maven-afhængigheder

For at starte, lad os se på de afhængigheder, der kræves for at begynde at arbejde 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 finde den nyeste version af disse Akka-biblioteker på Maven Central.

3. Oprettelse af en skuespiller

Som et eksempel bygger vi en HTTP API, der giver os mulighed for at administrere brugerressourcer. API'en understøtter to operationer:

  • oprettelse af en ny bruger
  • indlæser en eksisterende bruger

Før vi kan levere en HTTP API, vi bliver nødt til at implementere en aktør, der leverer de operationer, vi har brug for:

klasse UserActor udvider AbstractActor {privat UserService userService = ny UserService (); statiske rekvisitter rekvisitter () {returner 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 ()); sender () .tell (ny ActionPerformed (String.format ("Bruger% s oprettet.", createUserMessage.getUser (). getName ())), getSelf ()); }; } privat FI.UnitApply handleGetUser () {return getUserMessage -> {sender (). fortæl (userService.getUser (getUserMessage.getUserId ()), getSelf ()); }; }}

Dybest set udvider vi Abstrakt Skuespiller klasse og implementere dens createReceive () metode.

Inden for createReceive (), vi er kortlægning af indgående meddelelsestyper til metoder, der håndterer meddelelser af den respektive type.

Beskedstyperne er enkle, serielle containerklasser med nogle felter, der beskriver en bestemt handling. GetUserMessage og har et enkelt felt bruger ID for at identificere den bruger, der skal indlæses. CreateUserMessage indeholder en Bruger objekt med brugerdataene, vi har brug for for at oprette en ny bruger.

Senere ser vi, hvordan vi oversætter indgående HTTP-anmodninger til disse meddelelser.

I sidste ende delegerer vi alle beskeder til en UserService eksempel, som giver den forretningslogik, der er nødvendig til styring af vedvarende brugerobjekter.

Bemærk også rekvisitter() metode. Mens rekvisitter() metode er ikke nødvendig for at udvide Abstrakt Skuespiller, det vil komme godt med senere, når du opretter ActorSystem.

For en mere detaljeret diskussion om skuespillere, se vores introduktion til Akka Actors.

4. Definition af HTTP-ruter

At have en skuespiller, der udfører det egentlige arbejde for os, alt hvad vi har tilbage at gøre er at levere en HTTP API, der delegerer indgående HTTP-anmodninger til vores skuespiller.

Akka bruger begrebet ruter til at beskrive en HTTP API. For hver operation har vi brug for en rute.

For at oprette en HTTP-server udvider vi rammeklassen HttpApp og implementere ruter metode:

klasse UserServer udvider HttpApp {private final ActorRef userActor; Timeout timeout = ny Timeout (Duration.create (5, TimeUnit.SECONDS)); UserServer (ActorRef userActor) {this.userActor = userActor; } @Override offentlige ruteruter () {retursti ("brugere", denne :: postUser) .ellerElse (sti (segment ("brugere"). Skråstreg (longSegment ()), id -> rute (getUser (id)) )); } privat rute getUser (lang id) {retur get (() -> {CompletionStage bruger = PatternsCS.ask (userActor, ny GetUserMessage (id), timeout). derefter Anvend (obj -> (Valgfri) obj); return onSuccess (() -> bruger, udført -> {if (Performed.isPresent ()) Return Complete (StatusCodes.OK, Performed.get (), Jackson.marshaller ()); Ellers Return Complete (StatusCodes.NOT_FOUND); }); }); } privat rute postUser () {returrute (post (() -> enhed (Jackson.unmarshaller (User.class), bruger -> {CompletionStage userCreated = PatternsCS.ask (userActor, ny CreateUserMessage (bruger), timeout). derefter Anvend (obj -> (ActionPerformed) obj); return onSuccess (() -> userCreated, performed -> {return complete (StatusCodes.CREATED, Performed, Jackson.marshaller ());});}))); }} 

Nu er der en hel del kedelplade her, men bemærk at vi følger det samme mønster som før fra kortlægningsoperationer, denne gang som ruter. Lad os nedbryde det lidt.

Inden for getUser (), pakker vi simpelthen det indgående bruger-id i en besked af typen GetUserMessage og videresend denne besked til vores userActor.

Når skuespilleren har behandlet beskeden, vises onSuccess handler kaldes, hvor vi komplet HTTP-anmodningen ved at sende et svar med en bestemt HTTP-status og et bestemt JSON-organ. Vi bruger Jackson marshaller til at serieisere svaret fra skuespilleren i en JSON-streng.

Inden for postbruger (), vi gør tingene lidt anderledes, da vi forventer en JSON-krop i HTTP-anmodningen. Vi bruger enhed() metode til at kortlægge det indgående JSON-organ i en Bruger genstand, inden den pakkes ind i CreateUserMessage og videregive det til vores skuespiller. Igen bruger vi Jackson til at kortlægge mellem Java og JSON og omvendt.

Siden HttpApp forventer, at vi leverer en enkelt Rute objekt, vi kombinerer begge ruter til en enkelt inden for ruter metode. Her bruger vi sti direktiv til endelig at angive den URL-sti, hvor vores API skal være tilgængelig.

Vi binder ruten leveret af postbruger () til stien / brugere. Hvis den indgående anmodning ikke er en POST-anmodning, går Akka automatisk ind i ellers gren og forvent, at stien skal være / brugere / og HTTP-metoden skal være GET.

Hvis HTTP-metoden er GET, videresendes anmodningen til getUser () rute. Hvis brugeren ikke eksisterer, returnerer Akka HTTP-status 404 (ikke fundet). Hvis metoden hverken er en POST eller en GET, returnerer Akka HTTP-status 405 (Metoden er ikke tilladt).

For mere information om, hvordan du definerer HTTP-ruter med Akka, skal du kigge på Akka-dokumenterne.

5. Start af serveren

Når vi har oprettet en HttpApp implementering som ovenfor, kan vi starte vores HTTP-server med et par kodelinjer:

offentlig statisk ugyldig hoved (String [] args) kaster Undtagelse {ActorSystem system = ActorSystem.create ("userServer"); ActorRef userActor = system.actorOf (UserActor.props (), "userActor"); UserServer-server = ny UserServer (userActor); server.startServer ("localhost", 8080, system); }

Vi opretter simpelthen en ActorSystem med en enkelt aktør af typen UserActor og start serveren på lokal vært.

6. Konklusion

I denne artikel har vi lært om det grundlæggende i Akka HTTP med et eksempel, der viser, hvordan man opsætter en HTTP-server og udsætter slutpunkter for at oprette og indlæse ressourcer, svarende til en REST API.

Som sædvanlig kan kildekoden, der præsenteres her, findes på GitHub.