1. 概要

現在、フロントエンドコンポーネントとバックエンドコンポーネントは、多くの場合、Webアプリケーションを分離しています。 通常、APIは、フロントエンドコンポーネントまたはサードパーティのアプリ統合のバックエンドコンポーネントとして公開されます。

このようなシナリオでは、バックエンドAPIの適切な仕様を用意することが不可欠です。 同時に、APIドキュメントは、有益で、読みやすく、わかりやすいものである必要があります。

さらに、リファレンスドキュメントでは、APIのすべての変更について同時に説明する必要があります。 これを手動で実行するのは面倒な作業であるため、プロセスの自動化は避けられませんでした。

このチュートリアルでは、Swagger2仕様のSpringfox実装を使用して、SpringRESTWebサービスSwagger2を確認します。 現在OpenAPI3.0として知られている最新バージョンのSwagger仕様は、Spring docプロジェクトでより適切にサポートされており、ドキュメント化Spring RESTAPIに使用する必要があることに注意してください。

Swaggerに慣れていない場合は、このチュートリアルを続行する前に、そのWebページにアクセスして詳細を確認してください。

2. 対象プロジェクト

使用するRESTサービスの作成は、この記事の範囲内ではありません。 適切なプロジェクトがすでにある場合は、それを使用してください。 そうでない場合は、これらのリンクから始めるのがよいでしょう。

3. Maven依存関係の追加

上記のように、Swagger仕様のSpringfox実装を使用します。 最新バージョンは、MavenCentralにあります。

これをMavenプロジェクトに追加するには、pom.xmlファイルに依存関係が必要です。

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>

3.1. 春のブート依存性

Spring Bootベースのプロジェクトの場合、単一のspringfox-boot-starter依存関係を追加するだけで十分です。

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

Spring Bootの親が管理するバージョンを使用して、必要な他のスターターを追加できます。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
</dependency>

4. Swagger2をプロジェクトに統合する

4.1. Java構成

Swaggerの構成は、主にDocketBeanを中心にしています。

@Configuration
public class SpringFoxConfig {                                    
    @Bean
    public Docket api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}

Docket Beanを定義した後、その select()メソッドは ApiSelectorBuilder のインスタンスを返します。これは、Swaggerによって公開されるエンドポイントを制御する方法を提供します。

RequestHandlerSelectorsおよびPathSelectorsを使用して、RequestHandlerを選択するための述語を構成できます。 両方にany()を使用すると、API全体のドキュメントがSwaggerから利用できるようになります。

4.2. スプリングブートなしの構成

プレーンなSpringプロジェクトでは、Swagger2を明示的に有効にする必要があります。 そのためには、構成クラスで@EnableSwagger2WebMvcを使用する必要があります。

@Configuration
@EnableSwagger2WebMvc
public class SpringFoxConfig {                                    
}

さらに、Spring Bootがないと、リソースハンドラーを自動構成する余裕がありません。

Swagger UIは、 WebMvcConfigurerAdapter を拡張し、 @EnableWebMvc:で注釈が付けられたクラスの一部として構成する必要がある一連のリソースを追加します。

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");

    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
}

4.3. 検証

Springfoxが機能していることを確認するには、ブラウザで次のURLにアクセスします。

http:// localhost:8080 / spring-security-rest / api / v2 / api-docs

その結果、多数のキーと値のペアを含むJSON応答が生成されますが、これは人間が判読できる形式ではありません。 幸い、Swaggerはこの目的のために SwaggerUIを提供します。

5. Swagger UI

Swagger UIは、Swaggerで生成されたAPIドキュメントとのユーザーの対話をはるかに簡単にする組み込みソリューションです。

5.1. SpringfoxのSwaggerUIを有効にする

Swagger UIを使用するには、Mavenの依存関係を追加する必要があります。

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

これで、次のサイトにアクセスしてブラウザでテストできます。

http:// localhost:8080 / your-app-root / swagger-ui /

ちなみに、この場合、正確なURLは次のようになります。

http:// localhost:8080 / spring-security-rest / api / swagger-ui /

結果は次のようになります。

5.2. Swaggerドキュメントの調査

Swaggerの応答には、アプリケーションで定義されているすべてのコントローラーリストがあります。 それらのいずれかをクリックすると、有効なHTTPメソッド( DELETE GET HEAD OPTIONS PATCHが一覧表示されます。 ]、 POST PUT )。

各メソッドを展開すると、応答ステータス、コンテンツタイプ、パラメータのリストなど、追加の有用なデータが提供されます。 UIを使用して各方法を試すこともできます。

コードベースと同期するSwaggerの機能は非常に重要です。 これを実証するために、アプリケーションに新しいコントローラーを追加できます。

@RestController
public class CustomController {

    @RequestMapping(value = "/custom", method = RequestMethod.POST)
    public String custom() {
        return "custom";
    }
}

ここで、Swaggerのドキュメントを更新すると、コントローラーのリストにcustom-controllerが表示されます。 ご存知のように、Swaggerの応答に示されているメソッドは1つ( POST )のみです。

6. Spring Data REST

Springfoxは、springfox-data-restライブラリを介してSpringDataRESTのサポートを提供します。

Spring Bootは、クラスパスでspring-boot-starter-data-restを検出すると、自動構成を処理します。

次に、Userという名前のエンティティを作成しましょう。

@Entity
public class User {
    @Id
    private Long id;
    private String firstName;
    private int age;
    private String email;

    // getters and setters
}

次に、 UserRepository を作成して、UserエンティティにCRUD操作を追加します。

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}

最後に、SpringDataRestConfigurationクラスをSpringFoxConfigクラスにインポートします。

@EnableSwagger2WebMvc
@Import(SpringDataRestConfiguration.class)
public class SpringFoxConfig {
    //...
}

注:ライブラリのバージョン3の @ EnableSwagger2 アノテーションに取って代わったため、Swaggerを有効にするために @EnableSwagger2WebMvcアノテーションを使用しました。

アプリケーションを再起動して、Spring DataRESTAPIの仕様を生成してみましょう。

SpringfoxがGET POST、PUT、PATCH、DELETEなどのHTTPメソッドを使用してUserエンティティの仕様を生成したことがわかります。[ X167X]

7. Beanの検証

Springfoxは、springfox-bean-validatorsライブラリを介してbeanvalidationアノテーションもサポートしています。

まず、Mavenの依存関係をpom.xmlに追加します。

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-bean-validators</artifactId>
    <version>2.9.2</version>
</dependency>

繰り返しますが、 Spring Bootを使用する場合、上記の依存関係を明示的に指定する必要はありません

次に、@NotNull@Minなどの検証アノテーションをUserエンティティに追加しましょう。

@Entity
public class User {
    //...
    
    @NotNull(message = "First Name cannot be null")
    private String firstName;
    
    @Min(value = 15, message = "Age should not be less than 15")
    @Max(value = 65, message = "Age should not be greater than 65")
    private int age;
}

最後に、BeanValidatorPluginsConfigurationクラスをSpringFoxConfigクラスにインポートします。

@EnableSwagger2
@Import(BeanValidatorPluginsConfiguration.class)
public class SpringFoxConfig {
    //...
}

API仕様の変更点を見てみましょう。

ここで、UserモデルのfirstName*requiredがあることがわかります。 また、minimumおよびmaximumの値は、ageに対して定義されています。

8. プラグイン

API仕様に特定の機能を追加するために、Springfoxプラグインを作成できます。 プラグインは、モデルやプロパティの強化からカスタムAPIリストやデフォルトまで、さまざまな機能を提供できます。

Springfoxは、spiモジュールを介したプラグインの作成をサポートしています。 spiモジュールは、カスタムプラグインを実装するための拡張フックとして機能する ModelBuilderPlugin ModelPropertyBuilderPlugin ApiListingBuilderPluginなどのいくつかのインターフェイスを提供します。

機能を示すために、Userモデルのemailプロパティを強化するプラグインを作成しましょう。 ModelPropertyBuilderPlugin インターフェースを使用して、patternexampleの値を設定します。

まず、 EmailAnnotationPlugin クラスを作成し、 supports メソッドをオーバーライドして、Swagger1.2やSwagger2などのドキュメントタイプを許可します。

@Component
@Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER)
public class EmailAnnotationPlugin implements ModelPropertyBuilderPlugin {
    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }
}

次に、ModelPropertyBuilderPluginapplyメソッドをオーバーライドして、ビルダープロパティの値を設定します。

@Override
public void apply(ModelPropertyContext context) {
    Optional<Email> email = annotationFromBean(context, Email.class);
     if (email.isPresent()) {
        context.getSpecificationBuilder().facetBuilder(StringElementFacetBuilder.class)
          .pattern(email.get().regexp());
        context.getSpecificationBuilder().example("[email protected]");
    }
}

そのため、API仕様では、@Emailアノテーションが付けられたプロパティのpatternおよびexample値が表示されます。

次に、@EmailアノテーションをUserエンティティに追加します。

@Entity
public class User {
    //...

    @Email(regexp=".*@.*\\..*", message = "Email should be valid")
    private String email;
}

最後に、beanとして登録することにより、SpringFoxConfigクラスでEmailAnnotationPluginを有効にします。

@Import({BeanValidatorPluginsConfiguration.class})
public class SpringFoxConfig {
    //...

    @Bean
    public EmailAnnotationPlugin emailPlugin() {
        return new EmailAnnotationPlugin();
    }
}

EmailAnnotationPluginの動作を確認してみましょう。

pattern の値は、Userエンティティのemailプロパティからの同じ正規表現(。*@。*\\ .. *)であることがわかります。 。

同様に、 example [email protected])の値は、EmailAnnotationPluginapplyメソッドで定義されているものと同じです。

9. 高度な構成

アプリケーションのDocket Beanは、APIドキュメントの生成プロセスをより細かく制御できるように構成できます。

9.1. Swaggerの応答用のフィルタリングAPI

API全体のドキュメントを公開することが常に望ましいとは限りません。 Docketクラスのapis()メソッドと path()メソッドにパラメーターを渡すことで、Swaggerの応答を制限できます。

上記のように、 RequestHandlerSelectors では、anyまたはnone述語を使用できますが、基本パッケージ、クラスアノテーション、およびメソッドに従ってAPIをフィルタリングするためにも使用できます。注釈。

PathSelectors は、アプリケーションのリクエストパスをスキャンする述語による追加のフィルタリングを提供します。 any() none()、 regex()、または ant()を使用できます。

以下の例では、 ant()述語を使用して、特定のパッケージのコントローラーのみを特定のパスで含めるようにSwaggerに指示します。

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()                                       
      .apis(RequestHandlerSelectors.basePackage("com.baeldung.web.controller"))
      .paths(PathSelectors.ant("/foos/*"))                     
      .build();
}

9.2. カスタム情報

Swaggerは、「Api Documentation」、「Created by Contact Email」、「Apache 2.0」など、カスタマイズ可能なデフォルト値も応答に提供します。

これらの値を変更するには、 apiInfo(ApiInfo apiInfo)メソッド—APIに関するカスタム情報を含むApiInfoクラスを使用できます。

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()
      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
      .paths(PathSelectors.ant("/foos/*"))
      .build()
      .apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
    return new ApiInfo(
      "My REST API", 
      "Some custom description of API.", 
      "API TOS", 
      "Terms of service", 
      new Contact("John Doe", "www.example.com", "[email protected]"), 
      "License of API", "API license URL", Collections.emptyList());
}

9.3. カスタムメソッドの応答メッセージ

Swaggerを使用すると、HTTPメソッドの応答メッセージをDocketglobalResponses()メソッドを介してグローバルにオーバーライドできます。

まず、デフォルトの応答メッセージを使用しないようにSwaggerに指示する必要があります。 すべてのGETメソッドの500および403応答メッセージをオーバーライドするとします。

これを実現するには、 Docket の初期化ブロックにいくつかのコードを追加する必要があります(わかりやすくするために、元のコードは除外されています)。

.useDefaultResponseMessages(false)
.globalResponses(HttpMethod.GET, newArrayList(
    new ResponseBuilder().code("500")
        .description("500 message").build(),
    new ResponseBuilder().code("403")
        .description("Forbidden!!!!!").build()
));

10. OAuthで保護されたAPIを使用したSwaggerUI

Swagger UIは、これまでここで十分に説明してきた非常に便利な機能を多数提供します。 ただし、APIが保護されていてアクセスできない場合、これらのほとんどを実際に使用することはできません。

この例の認証コード付与タイプを使用して、SwaggerがOAuthで保護されたAPIにアクセスできるようにする方法を見てみましょう。

SecuritySchemeおよびSecurityContextサポートを使用して、セキュリティで保護されたAPIにアクセスするようにSwaggerを構成します。

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
        .apis(RequestHandlerSelectors.any())
        .paths(PathSelectors.any())
        .build()
        .securitySchemes(Arrays.asList(securityScheme()))
        .securityContexts(Arrays.asList(securityContext()));
}

10.1. セキュリティ構成

Swagger構成でSecurityConfiguration beanを定義し、いくつかのデフォルトを設定します。

@Bean
public SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder()
        .clientId(CLIENT_ID)
        .clientSecret(CLIENT_SECRET)
        .scopeSeparator(" ")
        .useBasicAuthenticationWithAccessCodeGrant(true)
        .build();
}

10.2. SecurityScheme

次に、SecuritySchemeを定義します。 これは、APIがどのように保護されているかを説明するために使用されます(基本認証、OAuth2など)。

ここでは、リソースサーバーを保護するために使用されるOAuthスキームを定義します。

private SecurityScheme securityScheme() {
    GrantType grantType = new AuthorizationCodeGrantBuilder()
        .tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/token", "oauthtoken"))
        .tokenRequestEndpoint(
          new TokenRequestEndpoint(AUTH_SERVER + "/authorize", CLIENT_ID, CLIENT_SECRET))
        .build();

    SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
        .grantTypes(Arrays.asList(grantType))
        .scopes(Arrays.asList(scopes()))
        .build();
    return oauth;
}

承認コード付与タイプを使用したことに注意してください。このタイプには、トークンエンドポイントとOAuth2承認サーバーの承認URLを提供する必要があります。

そして、これが私たちが定義する必要のあるスコープです:

private AuthorizationScope[] scopes() {
    AuthorizationScope[] scopes = { 
      new AuthorizationScope("read", "for read operations"), 
      new AuthorizationScope("write", "for write operations"), 
      new AuthorizationScope("foo", "Access foo API") };
    return scopes;
}

これらは、 / foosAPI用にアプリケーションで実際に定義したスコープと同期します。

10.3. SecurityContext

最後に、サンプルAPIのSecurityContextを定義する必要があります。

private SecurityContext securityContext() {
    return SecurityContext.builder()
      .securityReferences(
        Arrays.asList(new SecurityReference("spring_oauth", scopes())))
      .forPaths(PathSelectors.regex("/foos.*"))
      .build();
}

ここで参照で使用した名前( spring_oauth )が、以前にSecuritySchemeで使用した名前とどのように同期するかに注意してください。

10.4. テスト

すべての設定が完了し、準備が整ったので、Swagger UIを見て、FooAPIにアクセスしてみましょう。

SwaggerUIにローカルでアクセスできます。

http://localhost:8082/spring-security-oauth-resource/swagger-ui.html

ご覧のとおり、セキュリティ構成により、新しい[承認]ボタンが表示されます。

[承認]ボタンをクリックすると、次のポップアップが表示され、SwaggerUIが保護されたAPIにアクセスすることを承認できます。

ご了承ください:

  • CLIENT_IDとCLIENT_SECRETは、以前に事前構成したので、すでに確認できます(ただし、変更することはできます)。
  • これで、必要なスコープを選択できます。

保護されたAPIのマークは次のとおりです。

そしてついに、APIをヒットできるようになりました。

もちろん、このセキュリティ構成がアクティブになっているので、SwaggerUIを外部に公開する方法に注意する必要があることは言うまでもありません。

11. 結論

この記事では、SpringRESTAPIのドキュメントを生成するようにSwagger2を設定しました。 また、Swaggerの出力を視覚化およびカスタマイズする方法についても検討しました。 そして最後に、Swaggerの単純なOAuth構成を確認しました。

このチュートリアルの完全な実装は、GitHubプロジェクトにあります。 ブートプロジェクトのセットアップを確認するには、このGitHubモジュールを確認してください。

OAuthセクションのコードは、spring-security-oauthリポジトリで入手できます。

また、REST With Spring の学生の場合は、モジュール7のレッスン1に進んで、SpringとSpring Bootを使用したSwaggerのセットアップについて詳しく説明してください。