Web APIを実装する(2)
リクエストURL内のパスパラメータを取得する
一昔前であれば、リクエストのパラメータをプログラム側で取得する際にはリクエストパラメータを利用するのが当たり前でしたが、ここ最近、Rest APIなどの場合にはパス内にパラメータを含めるようになりました。
例えば、リスト4は/item/36のようなリクエストがあった場合に"36"という文字列をパラメータとして扱うためのサンプルコードです。
@GetMapping("/item/{id}") // (1) パスパラメータの指定 public Response itemAction(@PathVariable("id") String id){ // (2) パスパラメータからの値の取得 }
(1)では、{id}という記述を使ってパスパラメータを指定します。また、パスパラメータとして指定したパラメータは(2)のように@PathVariableを使って取得できます。
idが必ず数字という制限をかけたい場合には、{id:^[0-9]+$}のように正規表現を使って記述することもできます。
ただし、筆者はあまりURLレベルでこういったチェックは行わないようにしています。もし、idにアルファベットなどを指定した場合には、このパスには一致しなくなるので対象のパスが見つからないことになるからです。
しかし、実際には、入力値エラーとして処理したい場合が多くあります。この場合には、パスに一致してほしいために個別の理由がない場合には正規表現などはあまり利用していません。
Beanのライフタイムを指定するアノテーション(@Scope)
Beanとして登録されるクラスはデフォルトの動作として起動時に一度だけインスタンスが作成され、同じインスタンスが利用されます。
このデフォルトの定義を変更するときには、@Scopeアノテーションを利用します。利用できるスコープには、以下の表3が利用可能です。
スコープ名 | 概要 |
---|---|
singleton | スコープを指定しない場合と同様。起動時に一度だけインスタンスを作成し、同じインスタンスを共有する。 |
prototype | 取得時に毎回新しいインスタンスを作成する。 |
request | HTTPでのリクエストごとに生成する。Webアプリケーションの場合のみ有効です。 |
session | HTTPでのセッション単位で生成します。Webアプリケーションの場合のみ有効です。 |
application | サーブレットコンテキスト単位で生成します。Webアプリケーションの場合のみ有効です。 |
websocket | WebSocketの接続単位で生成します。Webアプリケーションの場合のみ有効です。 |
サービスなどではデフォルトのsingletonでの利用が一般的ではありますが、Web APIの場合にはリクエストごとにインスタンスを生成した方が良いケースが多いためrequestを指定します。
エラー処理を行うコントローラの定義
コントローラ内でエラーが発生したときには、それらのエラーに応じたレスポンスの定義をする場合が一般的です。従って、各個別の実装でエラーが起きても共通したエラー処理を記述したくなります。
そのような場合、図4のようにSpring MVCではエラー処理を行うためのコントローラを@ControllerAdviceアノテーションを使って作成します。
リスト5は、サンプルアプリケーションでの@ControllerAdviceの利用例です。
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice // (1) @ControllerAdviceの指定 public class ErrorController { // (省略) @ExceptionHandler(ValidationException.class) // (2) 処理する例外クラスの指定 @ResponseStatus(HttpStatus.BAD_REQUEST) // (3) レスポンスステータス public Response handleValidationException(HttpServletRequest req, ValidationException ex){ return Response.createErrorResponse(ex); } // (4) 他の例外の指定 @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Response handleException(HttpServletRequest request, Exception ex){ return Response.createErrorResponse(ex); } }
(1)では@ControllerAdviceと@ResponseBodyの指定が定義された@RestControllerAdviceを指定します。
次に、(2)でコントローラ内で発生した例外に応じたクラスを@ExceptionHandlerで指定します。(3)でレスポンスのHTTPステータスコードを指定します。
同様に(4)のように他の例外クラスについても指定します。