SpringとJava Configを使用してREST APIを構築する
1. 概要
この記事では、set up REST in Spring –コントローラーとHTTP応答コード、ペイロードマーシャリングの構成、およびコンテンツネゴシエーションの方法を示します。
参考文献:
Spring @ResponseStatusを使用してHTTPステータスコードを設定する
@ResponseStatusアノテーションと、それを使用して応答ステータスコードを設定する方法をご覧ください。
Spring @Controllerおよび@RestControllerアノテーション
Spring MVCの@Controllerアノテーションと@RestControllerアノテーションの違いについて学びます。
2. SpringのRESTを理解する
Springフレームワークは、RESTfulサービスを作成する2つの方法をサポートしています。
-
ModelAndViewでMVCを使用する
-
HTTPメッセージコンバーターの使用
ModelAndViewのアプローチは古く、文書化されていますが、より冗長で構成が重いです。 RESTパラダイムを古いモデルに押し付けようとしますが、問題がないわけではありません。 Springチームはこれを理解し、Spring 3.0からファーストクラスのRESTサポートを提供しました。
The new approach, based on HttpMessageConverter and annotations, is much more lightweight and easy to implement.構成は最小限であり、RESTfulサービスに期待するものに対して適切なデフォルトを提供します。
3. Java構成
@Configuration
@EnableWebMvc
public class WebConfig{
//
}
新しい@EnableWebMvcアノテーションは、いくつかの便利な機能を実行します。具体的には、RESTの場合、クラスパス上のJacksonとJAXB 2の存在を検出し、デフォルトのJSONおよびXMLコンバーターを自動的に作成して登録します。 注釈の機能は、XMLバージョンと同等です。
これは近道であり、多くの状況で役立つかもしれませんが、完璧ではありません。 より複雑な構成が必要な場合は、アノテーションを削除し、WebMvcConfigurationSupportを直接拡張します。
3.1. Spring Bootを使用する
@SpringBootApplicationアノテーションを使用していて、spring-webmvc libraryがクラスパス上にある場合、@EnableWebMvcアノテーションはa default autoconfigurationとともに自動的に追加されます。
@Configuration annotatedクラスにWebMvcConfigurerインターフェースを実装することで、この構成にMVC機能を追加できます。 WebMvcRegistrationsAdapterインスタンスを使用して、独自のRequestMappingHandlerMapping、RequestMappingHandlerAdapter、またはExceptionHandlerExceptionResolver の実装を提供することもできます。
最後に、Spring BootのMVC機能を破棄してカスタム構成を宣言する場合は、@EnableWebMvcアノテーションを使用して宣言できます。
4. Springコンテキストのテスト
Spring 3.1以降、@Configurationクラスのファーストクラスのテストサポートが提供されます。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = {WebConfig.class, PersistenceConfig.class},
loader = AnnotationConfigContextLoader.class)
public class SpringContextIntegrationTest {
@Test
public void contextLoads(){
// When
}
}
@ContextConfigurationアノテーションを使用してJava構成クラスを指定しています。 新しいAnnotationConfigContextLoaderは、@ConfigurationクラスからBean定義をロードします。
WebConfig構成クラスは、提供されていないサーブレットコンテキストで実行する必要があるため、テストに含まれていないことに注意してください。
4.1. Spring Bootを使用する
Spring Bootは、より直感的な方法でテスト用のSpringApplicationContextを設定するためのいくつかのアノテーションを提供します。
アプリケーション設定の特定のスライスのみをロードすることも、コンテキスト起動プロセス全体をシミュレートすることもできます。
たとえば、サーバーを起動せずにコンテキスト全体を作成する場合は、@SpringBootTestアノテーションを使用できます。
これが整ったら、@AutoConfigureMockMvcを追加して、MockMvc インスタンスを挿入し、HTTPリクエストを送信します:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FooControllerAppIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void whenTestApp_thenEmptyResponse() throws Exception {
this.mockMvc.perform(get("/foos")
.andExpect(status().isOk())
.andExpect(...);
}
}
コンテキスト全体の作成を回避し、MVCコントローラーのみをテストするために、@WebMvcTest:を使用できます。
@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerWebLayerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private IFooService service;
@Test()
public void whenTestMvcController_thenRetrieveExpectedResult() throws Exception {
// ...
this.mockMvc.perform(get("/foos")
.andExpect(...);
}
}
この主題に関する詳細情報はour ‘Testing in Spring Boot' articleにあります。
5. コントローラー
The @RestController is the central artifact in the entire Web Tier of the RESTful API.この投稿の目的のために、コントローラーは単純なRESTリソースをモデル化しています–Foo:
@RestController
@RequestMapping("/foos")
class FooController {
@Autowired
private IFooService service;
@GetMapping
public List findAll() {
return service.findAll();
}
@GetMapping(value = "/{id}")
public Foo findById(@PathVariable("id") Long id) {
return RestPreconditions.checkFound(service.findById(id));
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Long create(@RequestBody Foo resource) {
Preconditions.checkNotNull(resource);
return service.create(resource);
}
@PutMapping(value = "/{id}")
@ResponseStatus(HttpStatus.OK)
public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
Preconditions.checkNotNull(resource);
RestPreconditions.checkNotNull(service.getById(resource.getId()));
service.update(resource);
}
@DeleteMapping(value = "/{id}")
@ResponseStatus(HttpStatus.OK)
public void delete(@PathVariable("id") Long id) {
service.deleteById(id);
}
}
簡単なGuavaスタイルのRestPreconditionsユーティリティを使用していることに気付いたかもしれません。
public class RestPreconditions {
public static T checkFound(T resource) {
if (resource == null) {
throw new MyResourceNotFoundException();
}
return resource;
}
}
コントローラの実装は非公開です。これは、公開する必要がないためです。
通常、コントローラーは依存関係のチェーンの最後です。 Springフロントコントローラー(DispatcherServlet)からHTTPリクエストを受信し、それらをサービスレイヤーに転送するだけです。 コントローラーを直接参照して挿入または操作する必要があるユースケースがない場合は、パブリックとして宣言しないことをお勧めします。
要求のマッピングは簡単です。 As with any controller, the actual value of the mapping, as well as the HTTP method, determine the target method for the request. @RequestBodyは、メソッドのパラメーターをHTTP要求の本体にバインドしますが、@ResponseBodyは、応答と戻り値の型に対して同じことを行います。
@RestController はshorthandであり、クラス.に@ResponseBodyと @Controllerの両方のアノテーションが含まれます。
また、正しいHTTPコンバーターを使用して、リソースがマーシャリングおよびアンマーシャリングされるようにします。 コンテントネゴシエーションは、主にAcceptヘッダーに基づいて、アクティブなコンバーターのどれを使用するかを選択するために行われますが、他のHTTPヘッダーを使用して表現を決定することもできます。
6. HTTP応答コードのマッピング
HTTP応答のステータスコードはRESTサービスの最も重要な部分の1つであり、サブジェクトはすぐに非常に複雑になる可能性があります。 これらを正しく取得することが、サービスを作成または中断する場合があります。
6.1. マップされていないリクエスト
Spring MVCは、マッピングのないリクエストを受信すると、そのリクエストは許可されていないと見なし、405 METHOD NOTALLOWEDをクライアントに返します。
また、405をクライアントに返すときにAllow HTTPヘッダーを含めて、許可する操作を指定することもお勧めします。 これはSpringMVCの標準的な動作であり、追加の構成は必要ありません。
6.2. 有効なマップされたリクエスト
マッピングのあるリクエストの場合、Spring MVCはリクエストが有効であると見なし、他にステータスコードが指定されていない場合は200 OKで応答します。
このため、コントローラーはcreate、update、およびdeleteのアクションに対して異なる@ResponseStatusを宣言しますが、getに対しては宣言しません。これにより、実際にはデフォルトの200が返されます。 OK。
6.3. クライアントエラー
クライアントエラーの場合、カスタム例外が定義され、適切なエラーコードにマップされます。
Web層のいずれかのレイヤーからこれらの例外を単にスローするだけで、Springは対応するステータスコードをHTTP応答にマップします。
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
//
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
//
}
これらの例外はREST APIの一部であるため、RESTに対応する適切なレイヤーでのみ使用する必要があります。たとえば、DAO / DAL層が存在する場合、例外を直接使用しないでください。
また、これらはチェック例外ではなく、ランタイム例外であることに注意してください。これは、Springの慣習とイディオムに沿っています。
6.4. @ExceptionHandlerの使用
特定のステータスコードにカスタム例外をマップする別のオプションは、コントローラーで@ExceptionHandlerアノテーションを使用することです。 このアプローチの問題は、アノテーションが定義されているコントローラーにのみ適用されることです。 これは、各コントローラーで個別に宣言する必要があることを意味します。
もちろん、SpringとSpring Bootの両方に、より柔軟性のあるways to handle errorsがあります。
7. Additional Maven Dependencies **
spring-webmvc依存関係required for the standard web applicationに加えて、RESTAPIのコンテンツマーシャリングとアンマーシャリングを設定する必要があります。
com.fasterxml.jackson.core
jackson-databind
2.9.8
javax.xml.bind
jaxb-api
2.3.1
runtime
これらは、RESTリソースの表現をJSONまたはXMLに変換するために使用されるライブラリです。
7.1. Spring Bootを使用する
JSON形式のリソースを取得する場合、Spring Bootはさまざまなライブラリ、つまりJackson、Gson、およびJSON-Bのサポートを提供します。
自動設定は、クラスパスにマッピングライブラリを含めるだけで実行されます。
通常、Webアプリケーションを開発している場合、we’ll just add the spring-boot-starter-web dependency and rely on it to include all the necessary artifacts to our project:
org.springframework.boot
spring-boot-starter-web
2.1.2.RELEASE
Spring BootはデフォルトでJacksonを使用します。
リソースをXML形式でシリアル化する場合は、Jackson XML拡張機能(jackson-dataformat-xml)を依存関係に追加するか、JAXB実装(JDKでデフォルトで提供)にフォールバックする必要があります。リソースの@XmlRootElementアノテーション。
8. 結論
このチュートリアルでは、SpringおよびJavaベースの構成を使用してRESTサービスを実装および構成する方法を示しました。
シリーズの次の記事では、Discoverability of the API、高度なコンテンツネゴシエーション、およびResource.の追加表現の操作に焦点を当てます。
この記事のすべてのコードはover on Githubで利用できます。 これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。