与时俱进:在JAX-RS API中采用OpenAPI v3.0.0
看到時(shí)間流逝真是太恐怖了! OpenAPI規(guī)范3.0.0是對(duì)Swagger規(guī)范的重大修改,大部分已于一年前發(fā)布,但是工具趕上了一段時(shí)間。 但是,隨著Swagger Core 2.0.0的最新正式發(fā)布,事情肯定會(huì)加速。
為了證明這一點(diǎn),著名的JAX-RS 2.1實(shí)現(xiàn)Apache CXF是OpenAPI 3.0.0的最早采用者之一,在今天的帖子中,我們將了解一下JAX-RS 2.1 API可以多么容易從中受益。
與往常一樣,為了使事情變得簡(jiǎn)單,我們將設(shè)計(jì)人員管理Web API,僅提供少量支持它的資源,這里沒(méi)有什么太令人興奮的。
POST /api/people GET /api/people/{email} GET /api/people DELETE /api/people/{email}我們的模型將包含一個(gè)Person類。
public class Person {private String email;private String firstName;private String lastName; }為了增加一點(diǎn)魔力,我們將使用Spring Boot來(lái)使我們盡快啟動(dòng)并運(yùn)行。 這樣,讓我們??開(kāi)始填充依賴項(xiàng)(假設(shè)我們使用Apache Maven進(jìn)行構(gòu)建管理)。
<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxrs</artifactId><version>3.2.4</version> </dependency>在最近的3.2.x版本中, Apache CXF基于Swagger Core 2.0.0引入了一個(gè)專門(mén)用于OpenAPI 3.0.0的新模塊cxf-rt-rs-service-description-openapi-v3 。
<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId><version>3.2.4</version> </dependency><dependency><groupId>org.webjars</groupId><artifactId>swagger-ui</artifactId><version>3.13.6</version> </dependency>Swagger UI的存在不是絕對(duì)必要的,但是它是探索API的非常有用且漂亮的工具(如果在classpath中可用, Apache CXF會(huì)將其無(wú)縫集成到您的應(yīng)用程序中,我們將在稍后介紹) 。
前提條件就位,讓我們做一些編碼! 在開(kāi)始之前,值得注意的是Swagger Core 2.0.0有很多方法可以為您的服務(wù)填充OpenAPI 3.0.0定義,包括屬性文件,注釋或以編程方式。 在這篇文章中,我們將僅使用注釋。
@OpenAPIDefinition(info = @Info(title = "People Management API",version = "0.0.1-SNAPSHOT",license = @License(name = "Apache 2.0 License",url = "http://www.apache.org/licenses/LICENSE-2.0.html")) ) @ApplicationPath("api") public class JaxRsApiApplication extends Application { }看起來(lái)非常簡(jiǎn)單, @ OpenAPIDefinition為我們所有的Web API設(shè)置了頂級(jí)定義。 移動(dòng)到PeopleRestService,我們只需添加@Tag注釋,那么,標(biāo)簽我們的API。
@Path( "/people" ) @Tag(name = "people") public class PeopleRestService {// ... }太棒了,到目前為止沒(méi)有什么復(fù)雜的。 最棘手的部分從Web API操作定義開(kāi)始,因此讓我們看一下第一個(gè)示例,即獲取所有人的操作。
@Produces(MediaType.APPLICATION_JSON) @GET @Operation(description = "List all people", responses = {@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Person.class))),responseCode = "200")} ) public Collection<Person> getPeople() {// ... }相當(dāng)多的注釋,但總的來(lái)說(shuō),看起來(lái)很干凈直接。 讓我們看一下另一個(gè),即通過(guò)其電子郵件地址查找此人的端點(diǎn)。
@Produces(MediaType.APPLICATION_JSON) @Path("/{email}") @GET @Operation(description = "Find person by e-mail", responses = {@ApiResponse(content = @Content(schema = @Schema(implementation = Person.class)), responseCode = "200"),@ApiResponse(responseCode = "404", description = "Person with such e-mail doesn't exists")} ) public Person findPerson(@Parameter(description = "E-Mail address to lookup for", required = true) @PathParam("email") final String email) {// ... }同樣,通過(guò)電子郵件刪除該人的操作看起來(lái)幾乎是相同的。
@Path("/{email}") @DELETE @Operation(description = "Delete existing person",responses = {@ApiResponse(responseCode = "204",description = "Person has been deleted"),@ApiResponse(responseCode = "404", description = "Person with such e-mail doesn't exists")} ) public Response deletePerson(@Parameter(description = "E-Mail address to lookup for", required = true ) @PathParam("email") final String email) {// ... }太好了,讓我們總結(jié)一下最后一個(gè)可以說(shuō)是最有趣的端點(diǎn),它增加了一個(gè)新人(使用@FormParam的選擇純粹是為了說(shuō)明API的不同風(fēng)格)。
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) @POST @Operation(description = "Create new person",responses = {@ApiResponse(content = @Content(schema = @Schema(implementation = Person.class), mediaType = MediaType.APPLICATION_JSON),headers = @Header(name = "Location"),responseCode = "201"),@ApiResponse(responseCode = "409", description = "Person with such e-mail already exists")} ) public Response addPerson(@Context final UriInfo uriInfo,@Parameter(description = "E-Mail", required = true) @FormParam("email") final String email, @Parameter(description = "First Name", required = true) @FormParam("firstName") final String firstName, @Parameter(description = "Last Name", required = true) @FormParam("lastName") final String lastName) {// ... }如果您有使用較舊的Swagger規(guī)范記錄Web API的經(jīng)驗(yàn),那么您可能會(huì)發(fā)現(xiàn)該方法非常熟悉,但更為冗長(zhǎng)(或者更確切地說(shuō) ,是形式化的)。 這是規(guī)范領(lǐng)導(dǎo)和社區(qū)所做的巨大工作的結(jié)果,以使其盡可能完整和可擴(kuò)展。
已定義和記錄了API,現(xiàn)在該嘗試一下了! 不過(guò),缺少的部分是Spring配置,在該配置中我們將初始化并公開(kāi)我們的JAX-RS Web服務(wù)。
@Configuration @EnableAutoConfiguration @ComponentScan(basePackageClasses = PeopleRestService.class) public class AppConfig {@Autowired private PeopleRestService peopleRestService;@Bean(destroyMethod = "destroy")public Server jaxRsServer(Bus bus) {final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();factory.setApplication(new JaxRsApiApplication());factory.setServiceBean(peopleRestService);factory.setProvider(new JacksonJsonProvider());factory.setFeatures(Arrays.asList(new OpenApiFeature()));factory.setBus(bus);factory.setAddress("/");return factory.create();}@Beanpublic ServletRegistrationBean cxfServlet() {final ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new CXFServlet(), "/api/*");servletRegistrationBean.setLoadOnStartup(1);return servletRegistrationBean;} }OpenApiFeature是這里的關(guān)鍵要素,它負(fù)責(zé)所有集成和自省。 Spring Boot應(yīng)用程序是完成圖片的最后一步。
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(AppConfig.class, args);} }讓我們立即構(gòu)建并運(yùn)行它:
mvn clean package java -jar target/jax-rs-2.1-openapi-0.0.1-SNAPSHOT.jar啟動(dòng)應(yīng)用程序后,我們的Web API的OpenAPI 3.0.0規(guī)范應(yīng)處于活動(dòng)狀態(tài),并可以JSON格式用于以下位置:
http://localhost:8080/api/openapi.json或使用YAML格式:
http://localhost:8080/api/openapi.json探索并使用我們的Web API會(huì)很棒嗎? 由于我們包含了Swagger UI依賴關(guān)系,因此不必理會(huì),只需導(dǎo)航到http:// localhost:8080 / api / api-docs?url = / api / openapi.json :
特別要注意的是,小圖標(biāo)Swagger UI會(huì)與您的API版本一起放置,以暗示其符合OpenAPI 3.0.0規(guī)范。
這里只需要注意,使用Spring Boot沒(méi)有什么特別的。 如果您在OSGi容器中使用Apache CXF (例如,例如Apache Karaf ),則還可以與OpenAPI 3.0.0集成(如果您對(duì)此主題感興趣,請(qǐng)查閱官方文檔和示例 )。
一切看起來(lái)都很簡(jiǎn)單,但是如何從Swagger規(guī)范的較舊版本遷移到OpenAPI 3.0.0呢? Apache CXF具有強(qiáng)大的功能, 可以即時(shí)轉(zhuǎn)換較舊的規(guī)范,但總的來(lái)說(shuō), OpenApi.Tools門(mén)戶是評(píng)估選項(xiàng)的正確位置。
您應(yīng)該遷移到OpenAPI 3.0.0嗎? 老實(shí)說(shuō),我相信您應(yīng)該,至少應(yīng)該嘗試進(jìn)行試驗(yàn),但是請(qǐng)注意,該工具還不夠成熟,請(qǐng)期待一些障礙(您可以通過(guò)提供補(bǔ)丁來(lái)克服這些障礙) )。 但無(wú)疑,前程似錦!
完整的項(xiàng)目資源可在Github上找到 。
翻譯自: https://www.javacodegeeks.com/2018/05/moving-with-the-times-towards-openapi-v3-0-0-adoption-in-jax-rs-apis.html
總結(jié)
以上是生活随笔為你收集整理的与时俱进:在JAX-RS API中采用OpenAPI v3.0.0的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 华为怎么自定义键盘皮肤
- 下一篇: 此网站已备案什么意思(此网站已备案)