Byg en REST API med Spring og Java Config

REST Top

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN

1. Oversigt

Denne artikel viser, hvordan man gør det opsæt REST om foråret - Controller- og HTTP-svarkoder, konfiguration af nyttelastforsamling og indholdsforhandling.

2. Forståelse af REST om foråret

Spring-rammen understøtter to måder at skabe RESTful-tjenester på:

  • bruger MVC med ModelAndView
  • ved hjælp af HTTP-meddelelsesomformere

Det ModelAndView tilgang er ældre og meget bedre dokumenteret, men også mere detaljeret og konfigurationstung. Det forsøger at skovle REST-paradigmet ind i den gamle model, hvilket ikke er uden problemer. Spring-teamet forstod dette og leverede førsteklasses REST-support startende med Spring 3.0.

Den nye tilgang, baseret på HttpMessageConverter og kommentarer, er meget mere let og nem at implementere. Konfiguration er minimal, og det giver fornuftige standarder for, hvad du ville forvente af en RESTful service.

3. Java-konfigurationen

@Configuration @EnableWebMvc offentlig klasse WebConfig {//}

Den nye @EnableWebMvc annotering gør nogle nyttige ting - specifikt i tilfælde af REST registrerer den eksistensen af ​​Jackson og JAXB 2 på klassestien og opretter og registrerer automatisk standard JSON- og XML-konvertere. Annotationens funktionalitet svarer til XML-versionen:

Dette er en genvej, og selvom det kan være nyttigt i mange situationer, er det ikke perfekt. Når der er behov for en mere kompleks konfiguration, skal du fjerne kommentaren og udvide den WebMvcConfigurationSupport direkte.

3.1. Brug af Spring Boot

Hvis vi bruger @SpringBootApplication kommentar og fjeder-webmvc biblioteket er på klassestien, så er @EnableWebMvc annotering tilføjes automatisk med en standard autokonfiguration.

Vi kan stadig tilføje MVC-funktionalitet til denne konfiguration ved at implementere WebMvcConfigurer interface på en @Konfiguration kommenteret klasse. Vi kan også bruge en WebMvcRegistrationsAdapter eksempel for at give vores egne RequestMappingHandlerMapping, RequestMappingHandlerAdapter, eller ExceptionHandlerExceptionResolver implementeringer.

Endelig, hvis vi vil kassere Spring Boot's MVC-funktioner og erklære en brugerdefineret konfiguration, kan vi gøre det ved at bruge @EnableWebMvc kommentar.

4. Test af foråret sammenhæng

Fra og med foråret 3.1 får vi førsteklasses teststøtte til @Konfiguration klasser:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {WebConfig.class, PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) public class SpringContextIntegrationTest {@Test public void contextLoads} (// {) //

Vi specificerer Java-konfigurationsklasser med @ContextConfiguration kommentar. Den nye AnnotationConfigContextLoader indlæser bønnedefinitionerne fra @Konfiguration klasser.

Bemærk, at WebConfig konfigurationsklassen var ikke inkluderet i testen, fordi den skal køre i en Servlet-kontekst, som ikke er angivet.

4.1. Brug af Spring Boot

Spring Boot giver flere kommentarer til opsætning af Spring ApplicationContext til vores tests på en mere intuitiv måde.

Vi kan kun indlæse et bestemt stykke af applikationskonfigurationen, eller vi kan simulere hele kontekstens opstartsproces.

For eksempel kan vi bruge @SpringBootTest kommentar, hvis vi ønsker, at hele konteksten skal oprettes uden at starte serveren.

Med det på plads kan vi derefter tilføje @AutoConfigureMockMvc at injicere en MockMvc forekomst og send HTTP-anmodninger:

@RunWith (SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc offentlig klasse FooControllerAppIntegrationTest {@Autowired privat MockMvc mockMvc; @Test offentlig ugyldig når TestApp_thenEmptyResponse () kaster Undtagelse {this.mockMvc.perform (get ("/ foos") .andExpect (status (). IsOk ()). AndExpect (...);}}

For at undgå at skabe hele konteksten og kun teste vores MVC-controllere, kan vi bruge @WebMvcTest:

@RunWith (SpringRunner.class) @WebMvcTest (FooController.class) offentlig klasse FooControllerWebLayerIntegrationTest {@Autowired privat MockMvc mockMvc; @MockBean privat IFooService-tjeneste; @Test () offentlig ugyldig når TestMvcController_thenRetrieveExpectedResult () kaster undtagelse {// ... this.mockMvc.perform (get ("/ foos"). Og Expect (...);}}

Vi kan finde detaljerede oplysninger om dette emne i vores artikel 'Testing in Spring Boot'.

5. Controlleren

Det @RestController er den centrale artefakt i hele Web Tier i RESTful API. Med henblik på dette indlæg modellerer controlleren en simpel REST-ressource - Foo:

@RestController @RequestMapping ("/ foos") klasse FooController {@Autowired privat IFooService-tjeneste; @GetMapping offentlig liste findAll () {return service.findAll (); } @GetMapping (værdi = "/ {id}") offentlig Foo findById (@PathVariable ("id") Lang id) {return RestPreconditions.checkFound (service.findById (id)); } @PostMapping @ResponseStatus (HttpStatus.CREATED) offentlig lang oprettelse (@RequestBody Foo ressource) {Preconditions.checkNotNull (ressource); return service.create (ressource); } @PutMapping (værdi = "/ {id}") @ResponseStatus (HttpStatus.OK) offentlig ugyldig opdatering (@PathVariable ("id") Lang id, @RequestBody Foo ressource) {Preconditions.checkNotNull (ressource); RestPreconditions.checkNotNull (service.getById (resource.getId ())); service.update (ressource); } @DeleteMapping (værdi = "/ {id}") @ResponseStatus (HttpStatus.OK) offentlig ugyldig sletning (@PathVariable ("id") Lang id) {service.deleteById (id); }}

Du har måske bemærket, at jeg bruger en ligetil Guava-stil RestForudsætninger værktøj:

offentlig klasse RestPreconditions {public static T checkFound (T resource) {if (resource == null) {throw new MyResourceNotFoundException (); } returnere ressource }}

Controllerimplementeringen er ikke-offentlig - det er fordi den ikke behøver at være det.

Normalt er controlleren den sidste i kæden af ​​afhængigheder. Den modtager HTTP-anmodninger fra Spring front controller ( DispatcherServlet) og delegerer dem blot videre til et servicelag. Hvis der ikke er noget brugssag, hvor controlleren skal injiceres eller manipuleres gennem en direkte reference, foretrækker jeg ikke at erklære det som offentligt.

Anmodningstilknytningerne er ligetil. Som med enhver controller, er den faktiske værdi af kortlægningen såvel som HTTP-metoden skal du bestemme målmetoden for anmodningen. @RequestBody vil binde parametrene for metoden til selve HTTP-anmodningen, hvorimod @ResponseBody gør det samme for svar- og returtypen.

Det @RestController er en stenografi for at inkludere både @ResponseBody og @Kontrol kommentarer i vores klasse.

De sørger også for, at ressourcen bliver rangeret og ikke-parset ved hjælp af den korrekte HTTP-konverter. Indholdsforhandling finder sted for at vælge, hvilken af ​​de aktive konvertere der skal bruges, hovedsagelig baseret på Acceptere header, selvom andre HTTP-headere også kan bruges til at bestemme repræsentationen.

6. Kortlægning af HTTP-responskoder

HTTP-svarets statuskoder er en af ​​de vigtigste dele af REST-tjenesten, og emnet kan hurtigt blive meget kompliceret. At få disse ret kan være, hvad der gør eller bryder tjenesten.

6.1. Ikke-kortlagte anmodninger

Hvis Spring MVC modtager en anmodning, der ikke har en kortlægning, betragter den anmodningen som ikke tilladt og returnerer en 405 METODE, IKKE TILLADT tilbage til klienten.

Det er også en god praksis at medtage Give lov til HTTP-header, når du returnerer en 405 til klienten for at specificere, hvilke handlinger der er tilladt. Dette er standardopførelsen for Spring MVC og kræver ingen yderligere konfiguration.

6.2. Gyldige kortlagte anmodninger

For enhver anmodning, der har en kortlægning, anser Spring MVC anmodningen for gyldig og svarer med 200 OK, hvis der ikke er angivet nogen anden statuskode.

Det er på grund af dette, at controlleren erklærer forskellige @ResponseStatus til skab, opdatering og slet handlinger, men ikke til , som faktisk skal returnere standard 200 OK.

6.3. Klientfejl

I tilfælde af en klientfejl defineres brugerdefinerede undtagelser og kortlægges til de relevante fejlkoder.

Bare at kaste disse undtagelser fra et hvilket som helst af lagene på nettet vil sikre, at Spring kortlægger den tilsvarende statuskode på HTTP-svaret:

@ResponseStatus (HttpStatus.BAD_REQUEST) offentlig klasse BadRequestException udvider RuntimeException {//} @ResponseStatus (HttpStatus.NOT_FOUND) offentlig klasse ResourceNotFoundException udvider RuntimeException {//}

Disse undtagelser er en del af REST API og bør som sådan kun bruges i de passende lag svarende til REST; hvis der for eksempel findes et DAO / DAL-lag, bør det ikke bruge undtagelserne direkte.

Bemærk også, at disse ikke er markerede undtagelser, men undtagelser fra runtime - i tråd med Spring-praksis og -formsprog.

6.4. Ved brug af @ExceptionHandler

En anden mulighed for at kortlægge brugerdefinerede undtagelser på specifikke statuskoder er at bruge @ExceptionHandler kommentar i controlleren. Problemet med denne tilgang er, at kommentaren kun gælder for den controller, hvor den er defineret. Dette betyder, at vi skal erklære i hver controller individuelt.

Der er selvfølgelig flere måder at håndtere fejl i både Spring og Spring Boot, der giver mere fleksibilitet.

7. Yderligere Maven-afhængigheder

Ud over fjeder-webmvc afhængighed, der kræves for standardwebapplikationen, bliver vi nødt til at opsætte indholdsstyring og unmarshalling til REST API:

  com.fasterxml.jackson.core jackson-databind 2.9.8 javax.xml.bind jaxb-api 2.3.1 runtime 

Dette er de biblioteker, der bruges til at konvertere repræsentationen af ​​REST-ressourcen til enten JSON eller XML.

7.1. Brug af Spring Boot

Hvis vi ønsker at hente JSON-formaterede ressourcer, giver Spring Boot support til forskellige biblioteker, nemlig Jackson, Gson og JSON-B.

Autokonfiguration udføres ved blot at inkludere et af kortbibliotekerne i klassestien.

Normalt, hvis vi udvikler en webapplikation, vi tilføjer bare spring-boot-starter-web afhængighed og stole på, at det inkluderer alle de nødvendige artefakter til vores projekt:

 org.springframework.boot spring-boot-starter-web 2.1.2.RELEASE 

Spring Boot bruger Jackson som standard.

Hvis vi vil serieisere vores ressourcer i et XML-format, bliver vi nødt til at tilføje Jackson XML-udvidelsen (jackson-dataformat-xml) til vores afhængigheder eller tilbagefald til JAXB-implementeringen (leveres som standard i JDK) ved hjælp af @XmlRootElement kommentar på vores ressource.

8. Konklusion

Denne vejledning illustrerede, hvordan man implementerer og konfigurerer en REST-tjeneste ved hjælp af Spring- og Java-baseret konfiguration.

I de næste artikler i serien vil jeg fokusere på API's opdagelighed, avanceret indholdsforhandling og arbejde med yderligere repræsentationer af en Ressource.

Al koden i denne artikel er tilgængelig på Github. Dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.

REST bunden

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN