第54章 Swagger サポートでの JAX-RS エンドポイントの拡張
概要
CXF Swagger2Feature (org.apache.cxf.jaxrs.swagger.Swagger2Feature
) を使用すると、パブリッシュ済みの JAX-RS サービスエンドポイントを単純な設定で拡張することによって Swagger 2.0 ドキュメントを生成できます。
Swagger2Feature は、Spring Boot および Karaf 実装の両方でサポートされます。
54.1. Swagger2Feature オプション
Swagger2Feature では、以下のオプションを使用できます。
名前 | 説明 | デフォルト |
---|---|---|
|
コンテキストルートパス+( | null |
| 連絡先情報 | |
| 説明+ | アプリケーション" |
| セキュリティーフィルター+ | null |
| ホストおよびポート情報+ | null |
|
すべてのリソースをスキャンする際に、特定のパスを除外します ( | null |
| ライセンス+ | "Apache 2.0 ライセンス" |
| ライセンス URL+ | |
|
| false |
| リソースのスキャンが必要なパッケージ名のコンマ区切りの一覧++ | エンドポイントに設定されたサービスクラスの一覧 |
| 機能をフィルターとして実行します。 | false |
| swagger のドキュメントを生成します。 | true |
|
アノテーション付きの JAX-RS リソースを含むすべてのリソースをスキャンします ( | false |
| プロトコルスキーム+ | null |
| Swagger UI の設定 | null |
| サービス URL+ | null |
| タイトル+ | "サンプル REST アプリケーション" |
|
Swagger が | false |
| バージョン+ | "1.0.0" |
+ オプションは Swagger の BeanConfig で定義されます。
++ オプションは Swagger の ReaderConfig で定義されます。
Karaf 実装
ここでは、REST サービスが JAR ファイルで定義され、Fuse on Karaf コンテナーにデプロイされる Swagger2Feature を使用する方法について説明します。
==== クイックスタートの例
Fuse Software Downloads ページから Red Hat Fuse quickstarts
をダウンロードできます。
Quickstart zip ファイルには、CXF を使用して RESTful (JAX-RS) Web サービスを作成する方法と、Swagger を有効にして JAX-RS エンドポイントにアノテーションを付ける方法を実証するクイックスタートの /cxf/rest/
ディレクトリーが含まれています。
==== Swagger の有効化
Swagger を有効にするには、以下の操作が必要です。
CXF クラス (
org.apache.cxf.jaxrs.swagger.Swagger2Feature
) を<jaxrs:server>
定義に追加して CXF サービスを定義する XML ファイルを変更します。例は、例 55.4: XML ファイル を参照してください。
REST リソースクラスで以下を行います。
サービスで必要な各アノテーションの Swagger API アノテーションをインポートします。
import io.swagger.annotations.*
ここで、* は
Api
、ApiOperation
、ApiParam
、ApiResponse
、ApiResponses
などです。詳細は、
https://github.com/swagger-api/swagger-core/wiki/Annotations
を参照してください。例は、例 55.5: リソースクラスの例 を参照してください。
-
Swagger アノテーションを JAX-RS でアノテーションが付けられたエンドポイント (
@PATH
、@PUT
、@POST
、@GET
、@Produces
、@Consumes
、@DELETE
、@PathParam
など) に追加します。
例は、例 55.5: リソースクラスの例 を参照してください。
例 55.4: XML ファイル
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd"> <jaxrs:server id="customerService" address="/crm"> <jaxrs:serviceBeans> <ref component-id="customerSvc"/> </jaxrs:serviceBeans> <jaxrs:providers> <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/> </jaxrs:providers> <jaxrs:features> <bean class="org.apache.cxf.jaxrs.swagger.Swagger2Feature"> <property name="title" value="Fuse:CXF:Quickstarts - Customer Service" /> <property name="description" value="Sample REST-based Customer Service" /> <property name="version" value="${project.version}" /> </bean> </jaxrs:features> </jaxrs:server> <cxf:bus> <cxf:features> <cxf:logging /> </cxf:features> <cxf:properties> <entry key="skip.default.json.provider.registration" value="true" /> </cxf:properties> </cxf:bus> <bean id="customerSvc" class="org.jboss.fuse.quickstarts.cxf.rest.CustomerService"/> </blueprint>
例 55.5: リソースクラスの例
. . . import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; . . . @Path("/customerservice/") @Api(value = "/customerservice", description = "Operations about customerservice") public class CustomerService { private static final Logger LOG = LoggerFactory.getLogger(CustomerService.class); private MessageContext jaxrsContext; private long currentId = 123; private Map<Long, Customer> customers = new HashMap<>(); private Map<Long, Order> orders = new HashMap<>(); public CustomerService() { init(); } @GET @Path("/customers/{id}/") @Produces("application/xml") @ApiOperation(value = "Find Customer by ID", notes = "More notes about this method", response = Customer.class) @ApiResponses(value = { @ApiResponse(code = 500, message = "Invalid ID supplied"), @ApiResponse(code = 204, message = "Customer not found") }) public Customer getCustomer(@ApiParam(value = "ID of Customer to fetch", required = true) @PathParam("id") String id) { LOG.info("Invoking getCustomer, Customer id is: {}", id); long idNumber = Long.parseLong(id); return customers.get(idNumber); } @PUT @Path("/customers/") @Consumes({ "application/xml", "application/json" }) @ApiOperation(value = "Update an existing Customer") @ApiResponses(value = { @ApiResponse(code = 500, message = "Invalid ID supplied"), @ApiResponse(code = 204, message = "Customer not found") }) public Response updateCustomer(@ApiParam(value = "Customer object that needs to be updated", required = true) Customer customer) { LOG.info("Invoking updateCustomer, Customer name is: {}", customer.getName()); Customer c = customers.get(customer.getId()); Response r; if (c != null) { customers.put(customer.getId(), customer); r = Response.ok().build(); } else { r = Response.notModified().build(); } return r; } @POST @Path("/customers/") @Consumes({ "application/xml", "application/json" }) @ApiOperation(value = "Add a new Customer") @ApiResponses(value = { @ApiResponse(code = 500, message = "Invalid ID supplied"), }) public Response addCustomer(@ApiParam(value = "Customer object that needs to be updated", required = true) Customer customer) { LOG.info("Invoking addCustomer, Customer name is: {}", customer.getName()); customer.setId(++currentId); customers.put(customer.getId(), customer); if (jaxrsContext.getHttpHeaders().getMediaType().getSubtype().equals("json")) { return Response.ok().type("application/json").entity(customer).build(); } else { return Response.ok().type("application/xml").entity(customer).build(); } } @DELETE @Path("/customers/{id}/") @ApiOperation(value = "Delete Customer") @ApiResponses(value = { @ApiResponse(code = 500, message = "Invalid ID supplied"), @ApiResponse(code = 204, message = "Customer not found") }) public Response deleteCustomer(@ApiParam(value = "ID of Customer to delete", required = true) @PathParam("id") String id) { LOG.info("Invoking deleteCustomer, Customer id is: {}", id); long idNumber = Long.parseLong(id); Customer c = customers.get(idNumber); Response r; if (c != null) { r = Response.ok().build(); customers.remove(idNumber); } else { r = Response.notModified().build(); } return r; } . . . }
Spring Boot 実装
本セクションでは、Spring Boot で Swagger2Feature を使用する方法について説明します。
==== クイックスタートの例
クイックスタートサンプル (https://github.com/fabric8-quickstarts/spring-boot-cxf-jaxrs
) は、Spring Boot で Apache CXF を使用する方法を実証します。クイックスタートは Spring Boot を使用して、Swagger が有効な CXF JAX-RS エンドポイントが含まれるアプリケーションを設定します。
==== Swagger の有効化
Swagger を有効にするには、以下の操作が必要です。
REST アプリケーションで以下を行います。
Swagger2Feature をインポートする。
import org.apache.cxf.jaxrs.swagger.Swagger2Feature;
Swagger2Feature を CXF エンドポイントに追加する。
endpoint.setFeatures(Arrays.asList(new Swagger2Feature()));
例は、例 55.1: REST アプリケーションの例 を参照してください。
Java 実装ファイルで、サービスが必要とする各アノテーションの Swagger API アノテーションをインポートします。
import io.swagger.annotations.*
ここで、* は
Api
、ApiOperation
、ApiParam
、ApiResponse
、ApiResponses
などです。詳細は、
https://github.com/swagger-api/swagger-core/wiki/Annotations
を参照してください。例は、例 55.2: Java 実装ファイル を参照してください。
Java ファイルで、Swagger アノテーションを JAX-RS でアノテーションが付けられたエンドポイント (
@PATH
、@PUT
、@POST
、@GET
、@Produces
、@Consumes
、@DELETE
、@PathParam
など) に追加します。例は、例 55.3: Java ファイル を参照してください。
例 55.1: REST アプリケーションの例
package io.fabric8.quickstarts.cxf.jaxrs; import java.util.Arrays; import org.apache.cxf.Bus; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.swagger.Swagger2Feature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class SampleRestApplication { @Autowired private Bus bus; public static void main(String[] args) { SpringApplication.run(SampleRestApplication.class, args); } @Bean public Server rsServer() { // setup CXF-RS JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean(); endpoint.setBus(bus); endpoint.setServiceBeans(Arrays.<Object>asList(new HelloServiceImpl())); endpoint.setAddress("/"); endpoint.setFeatures(Arrays.asList(new Swagger2Feature())); return endpoint.create(); } }
例 55.2: Java 実装ファイル
import io.swagger.annotations.Api; @Api("/sayHello") public class HelloServiceImpl implements HelloService { public String welcome() { return "Welcome to the CXF RS Spring Boot application, append /{name} to call the hello service"; } public String sayHello(String a) { return "Hello " + a + ", Welcome to CXF RS Spring Boot World!!!"; } }
例 55.3: Java ファイル
package io.fabric8.quickstarts.cxf.jaxrs; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.springframework.stereotype.Service; @Path("/sayHello") @Service public interface HelloService { @GET @Path("") @Produces(MediaType.TEXT_PLAIN) String welcome(); @GET @Path("/{a}") @Produces(MediaType.TEXT_PLAIN) String sayHello(@PathParam("a") String a); }