Bygg en REST API med Spring og Java Config

REST Topp

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

1. Oversikt

Denne artikkelen viser hvordan du gjør det sette opp REST om våren - kontrolleren og HTTP-responskodene, konfigurering av nyttelastforsamling og innholdsforhandling.

2. Forstå REST om våren

Vårrammeverket støtter to måter å lage RESTful-tjenester på:

  • bruker MVC med ModelAndView
  • ved hjelp av HTTP-meldingsomformere

De ModelAndView tilnærmingen er eldre og mye bedre dokumentert, men også mer detaljert og konfigurasjonstung. Den prøver å skore REST-paradigmet i den gamle modellen, noe som ikke er uten problemer. Vårteamet forsto dette og ga førsteklasses REST-støtte fra og med våren 3.0.

Den nye tilnærmingen, basert på HttpMessageConverter og merknader, er mye mer lett og enkel å implementere. Konfigurasjon er minimal, og det gir fornuftige standardverdier for hva du forventer av en RESTful-tjeneste.

3. Java-konfigurasjonen

@Configuration @EnableWebMvc offentlig klasse WebConfig {//}

Den nye @EnableWebMvc kommentar gjør noen nyttige ting - spesielt når det gjelder REST, oppdager den eksistensen av Jackson og JAXB 2 på klassestien og oppretter og registrerer automatisk standard JSON- og XML-omformere. Merknadens funksjonalitet tilsvarer XML-versjonen:

Dette er en snarvei, og selv om det kan være nyttig i mange situasjoner, er det ikke perfekt. Når mer kompleks konfigurasjon er nødvendig, fjern merknaden og utvid den WebMvcConfigurationSupport direkte.

3.1. Bruke Spring Boot

Hvis vi bruker @SpringBootApplication kommentar og vår-webmvc biblioteket er på klassestien, så @EnableWebMvc merknader legges til automatisk med en standard autokonfigurasjon.

Vi kan fortsatt legge til MVC-funksjonalitet i denne konfigurasjonen ved å implementere WebMvcConfigurer grensesnitt på en @Konfigurasjon kommentert klasse. Vi kan også bruke en WebMvcRegistrationsAdapter eksempel for å gi vår egen RequestMappingHandlerMapping, RequestMappingHandlerAdapter, eller UnntakHandlerUttakLøser implementeringer.

Til slutt, hvis vi ønsker å forkaste Spring Boot's MVC-funksjoner og erklære en tilpasset konfigurasjon, kan vi gjøre det ved å bruke @EnableWebMvc kommentar.

4. Testing av vårkonteksten

Fra og med våren 3.1 får vi førsteklasses teststøtte for @Konfigurasjon klasser:

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

Vi spesifiserer Java-konfigurasjonsklassene med @ContextConfiguration kommentar. Den nye AnnotationConfigContextLoader laster bønnedefinisjonene fra @Konfigurasjon klasser.

Legg merke til at WebConfig konfigurasjonsklassen ble ikke inkludert i testen fordi den må kjøres i en Servlet-kontekst, som ikke er gitt.

4.1. Bruke Spring Boot

Spring Boot gir flere kommentarer for å sette opp våren ApplicationContext for testene våre på en mer intuitiv måte.

Vi kan bare laste inn en bestemt del av applikasjonskonfigurasjonen, eller vi kan simulere hele oppstartsprosessen for konteksten.

For eksempel kan vi bruke @SpringBootTest kommentar hvis vi vil at hele konteksten skal opprettes uten å starte serveren.

Med det på plass, kan vi deretter legge til @AutoConfigureMockMvc å injisere en MockMvc forekomst og send HTTP-forespørsler:

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

For å unngå å skape hele konteksten og bare teste MVC-kontrollerne våre, kan vi bruke @WebMvcTest:

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

Vi kan finne detaljert informasjon om dette emnet i vår artikkel om 'Testing in Spring Boot'.

5. Kontrolleren

De @RestController er den sentrale gjenstanden i hele Web Tier i RESTful API. For formålet med dette innlegget modellerer kontrolleren en enkel REST-ressurs - Foo:

@RestController @RequestMapping ("/ foos") klasse FooController {@Autowired privat IFooService-tjeneste; @GetMapping offentlig liste findAll () {return service.findAll (); } @GetMapping (value = "/ {id}") offentlig Foo findById (@PathVariable ("id") Lang id) {retur RestPreconditions.checkFound (service.findById (id)); } @PostMapping @ResponseStatus (HttpStatus.CREATED) public Long create (@RequestBody Foo resource) {Preconditions.checkNotNull (resource); return service.create (ressurs); } @PutMapping (value = "/ {id}") @ResponseStatus (HttpStatus.OK) offentlig ugyldig oppdatering (@PathVariable ("id") Lang id, @RequestBody Foo ressurs) {Preconditions.checkNotNull (ressurs); RestPreconditions.checkNotNull (service.getById (resource.getId ())); service.update (ressurs); } @DeleteMapping (value = "/ {id}") @ResponseStatus (HttpStatus.OK) sletting av tomrom (@PathVariable ("id") Lang id) {service.deleteById (id); }}

Du har kanskje lagt merke til at jeg bruker en grei Guava-stil RestForhold nytte:

public class RestPreconditions {public static T checkFound (T resource) {if (resource == null) {throw new MyResourceNotFoundException (); } returnere ressurs; }}

Kontrollerimplementeringen er ikke offentlig - dette er fordi den ikke trenger å være det.

Vanligvis er kontrolleren den siste i kjeden av avhengigheter. Den mottar HTTP-forespørsler fra vårfrontkontrolleren ( DispatcherServlet) og delegerer dem ganske enkelt videre til et tjenestelag. Hvis det ikke er noe brukstilfelle der kontrolleren må injiseres eller manipuleres gjennom en direkte referanse, foretrekker jeg ikke å erklære det som offentlig.

Kartleggingen av forespørslene er grei. Som med enhver kontroller, er den faktiske verdi av kartleggingen, så vel som HTTP-metoden, bestemmer målmetoden for forespørselen. @RequestBody vil binde parametrene til metoden til selve HTTP-forespørselen, mens @ResponseBody gjør det samme for respons- og returtypen.

De @RestController er en stenografi for å inkludere både @ResponseBody og @Kontrollør kommentarer i klassen vår.

De sørger også for at ressursen blir rangeret og unmarshalled ved hjelp av riktig HTTP-omformer. Innholdsforhandlinger vil finne sted for å velge hvilken av de aktive omformerne som skal brukes, hovedsakelig basert på Aksepterer topptekst, selv om andre HTTP-overskrifter også kan brukes til å bestemme representasjonen.

6. Kartlegge HTTP-responskodene

Statuskodene til HTTP-responsen er en av de viktigste delene av REST-tjenesten, og motivet kan fort bli veldig komplisert. Å få disse rett kan være det som gjør eller bryter tjenesten.

6.1. Ikke kartlagte forespørsler

Hvis Spring MVC mottar en forespørsel som ikke har en kartlegging, anser den forespørselen som ikke tillatt og returnerer en 405 METODE IKKE TILLATT tilbake til klienten.

Det er også en god praksis å inkludere Tillate HTTP-overskrift når du returnerer en 405 til klienten, for å spesifisere hvilke operasjoner som er tillatt. Dette er standardoppførselen til Spring MVC og krever ingen ekstra konfigurasjon.

6.2. Gyldige kartlagte forespørsler

For enhver forespørsel som har en kartlegging, anser Spring MVC forespørselen som gyldig og svarer med 200 OK hvis ingen annen statuskode er spesifisert på annen måte.

Det er på grunn av dette at kontrolleren erklærer annerledes @ResponseStatus for skape, Oppdater og slett handlinger, men ikke for , som faktisk skal returnere standard 200 OK.

6.3. Klientfeil

I tilfelle en klientfeil, defineres tilpassede unntak og tilordnes de aktuelle feilkodene.

Bare å kaste disse unntakene fra noen av lagene på nettnivået, vil sikre at Spring kartlegger den tilsvarende statuskoden på HTTP-responsen:

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

Disse unntakene er en del av REST API og bør som sådan bare brukes i de riktige lagene som tilsvarer REST; hvis det for eksempel eksisterer et DAO / DAL-lag, bør det ikke bruke unntakene direkte.

Vær også oppmerksom på at dette ikke er avmerkede unntak, men unntak for kjøretid - i tråd med vårpraksis og uttrykk.

6.4. Ved hjelp av @ExceptionHandler

Et annet alternativ for å kartlegge tilpassede unntak på spesifikke statuskoder er å bruke @ExceptionHandler kommentar i kontrolleren. Problemet med denne tilnærmingen er at merknaden bare gjelder kontrolleren der den er definert. Dette betyr at vi må erklære i hver kontroller individuelt.

Selvfølgelig er det flere måter å håndtere feil på både vår- og vårstøvler som gir mer fleksibilitet.

7. Ytterligere Maven-avhengigheter

I tillegg til det vår-webmvc avhengighet som kreves for standard webapplikasjon, må vi konfigurere innholdsstyring og unmarshalling for REST API:

  com.fasterxml.jackson.core jackson-databind 2.9.8 javax.xml.bind jaxb-api 2.3.1 kjøretid 

Dette er bibliotekene som brukes til å konvertere representasjonen av REST-ressursen til enten JSON eller XML.

7.1. Bruke Spring Boot

Hvis vi ønsker å hente JSON-formaterte ressurser, gir Spring Boot støtte for forskjellige biblioteker, nemlig Jackson, Gson og JSON-B.

Autokonfigurasjon utføres ved å bare inkludere noen av kartbibliotekene i klassestien.

Vanligvis, hvis vi utvikler en webapplikasjon, vi legger bare til spring-boot-starter-web avhengighet og stole på at den inkluderer alle nødvendige gjenstander til prosjektet vårt:

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

Spring Boot bruker Jackson som standard.

Hvis vi vil serieisere ressursene våre i et XML-format, må vi legge til Jackson XML-utvidelsen (jackson-dataformat-xml) til våre avhengigheter, eller tilbakefall til JAXB-implementeringen (gitt som standard i JDK) ved å bruke @XmlRootElement kommentar på ressursen vår.

8. Konklusjon

Denne opplæringen illustrerte hvordan du implementerer og konfigurerer en REST-tjeneste ved hjelp av vår- og Java-basert konfigurasjon.

I de neste artiklene i serien vil jeg fokusere på oppdagbarhet av API, avansert innholdsforhandling og arbeid med flere representasjoner av en Ressurs.

All koden i denne artikkelen er tilgjengelig på Github. Dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.

HVILLE bunnen

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET