001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.server.docs; 018 019import org.apache.juneau.bean.swagger.Swagger; 020import org.apache.juneau.bean.swagger.ui.*; 021import org.apache.juneau.http.response.*; 022import org.apache.juneau.marshall.*; 023import org.apache.juneau.marshall.html.*; 024import org.apache.juneau.marshall.jsonschema.*; 025import org.apache.juneau.rest.server.*; 026 027/** 028 * Mixin that publishes the Swagger v2 spec endpoint at {@code /api/*}. 029 * 030 * <p> 031 * Sibling of {@link SwaggerUiMixin} (HTML-first mount at {@code /swagger}), 032 * {@link OpenApiMixin} (OpenAPI 3.1 spec at {@code /openapi*}), and 033 * {@link RedocMixin} (HTML-first mount at {@code /redoc}). All four classes live in the 034 * {@code org.apache.juneau.rest.server.docs} api-docs mixin pack. 035 * 036 * <p> 037 * Compose into a host resource via {@link Rest#mixins() @Rest(mixins=SwaggerMixin.class)}; 038 * the {@code /api} URL becomes available alongside the host's own endpoints with no further wiring. 039 * 040 * <h5 class='section'>Configurable mount path:</h5> 041 * 042 * <p> 043 * The default mount {@code /api/*} can be overridden via the SVL variable 044 * {@code ${juneau.swagger.path:api}} — set via system property 045 * ({@code -Djuneau.swagger.path=swagger}), environment variable 046 * ({@code JUNEAU_SWAGGER_PATH=swagger}), or {@code Config} key 047 * ({@code juneau.swagger.path = swagger}) to change the runtime mount without subclassing. 048 * Resolution happens once at {@link RestContext} construction time (SVL resolution in {@code @RestOp(path)}). 049 * 050 * <p> 051 * Override accepts bare token ({@code api}), leading slash ({@code /api}), trailing slash 052 * ({@code api/}), or wildcard suffix ({@code /api/*}) — all resolve to the same mount. 053 * 054 * <h5 class='section'>Mixin-only deployment:</h5> 055 * 056 * <p> 057 * This resource is designed for composition via {@code @Rest(mixins=...)}. The mount path is 058 * pinned at the op level by {@link RestGet @RestGet(path="/{juneau.swagger.path:api}/*")} on 059 * {@link #getSwagger}; a class-level {@code @Rest(paths=...)} declaration would be silently 060 * ignored under the mixin pattern (see {@link Rest#paths() @Rest(paths)} Javadoc). 061 * 062 * <h5 class='figure'>Composition example:</h5> 063 * 064 * <p class='bjava'> 065 * <ja>@Rest</ja>(path=<js>"/myresource"</js>, mixins=SwaggerMixin.<jk>class</jk>) 066 * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { 067 * <ja>@RestGet</ja>(<js>"/items"</js>) <jk>public</jk> List<Item> items() { ... } 068 * <jc>// Now also serves /myresource/api with the Swagger v2 spec for this resource.</jc> 069 * } 070 * </p> 071 * 072 * <h5 class='section'>Content negotiation:</h5> 073 * 074 * <p> 075 * Standard Juneau content negotiation. {@code Accept: text/html} renders the Swagger-UI HTML view 076 * via the {@link SwaggerUI} per-media-type swap; other accept types serialize the 077 * {@link Swagger} bean using the host's serializer set. 078 * </p> 079 * 080 * <h5 class='section'>See Also:</h5><ul> 081 * <li class='jc'>{@link SwaggerUiMixin} 082 * <li class='jc'>{@link OpenApiMixin} 083 * <li class='jc'>{@link RedocMixin} 084 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerComposition">REST Server — Mixins and Multi-Mount Paths</a> 085 * </ul> 086 * 087 * @since 10.0.0 088 */ 089// @formatter:off 090@Rest 091@JsonSchemaConfig( 092 addDescriptionsTo="bean,collection,array,map,enum", 093 addExamplesTo="bean,collection,array,map", 094 ignoreTypes="Swagger,org.apache.juneau.bean.html5.*", 095 useBeanDefs="true" 096) 097public class SwaggerMixin { 098 099 /** 100 * [GET /api] — emit the Swagger v2 spec for this resource. 101 * 102 * @param req The current REST request. 103 * @return The Swagger document. 104 * @throws NotFound If no Swagger document is available for this resource. 105 */ 106 @RestGet( 107 path="/#{pathToken(${juneau.swagger.path:api})}/*", 108 summary="Swagger documentation", 109 description="Swagger v2 documentation for this resource." 110 ) 111 @HtmlDocConfig( 112 rank=10, 113 navlinks={ 114 "back: servlet:/", 115 "json: servlet:/api?Accept=text/json&plainText=true" 116 }, 117 aside="NONE" 118 ) 119 @MarshalledConfig( 120 swaps={ 121 SwaggerUI.class 122 } 123 ) 124 public Swagger getSwagger(RestRequest req) { 125 return req.getSwagger().orElseThrow(NotFound::new); 126 } 127}