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-UI HTML view at {@code /swagger}. 029 * 030 * <p> 031 * Sibling of {@link SwaggerMixin} (Swagger v2 spec at {@code /api}), 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 * Declares {@link Rest#mixins() @Rest(mixins={SwaggerMixin.class})} so transitive resolution 038 * pulls in {@code SwaggerMixin} (and its {@code /api} mount) automatically when this mixin 039 * is composed into a host. The two endpoints share the same Swagger document; they differ only in 040 * URL surface and content-negotiation defaults. 041 * 042 * <h5 class='section'>Configurable mount path:</h5> 043 * 044 * <p> 045 * The default mount {@code /swagger/*} can be overridden via the SVL variable 046 * {@code ${juneau.swaggerui.path:swagger}} — set via system property 047 * ({@code -Djuneau.swaggerui.path=docs}), environment variable 048 * ({@code JUNEAU_SWAGGERUI_PATH=docs}), or {@code Config} key 049 * ({@code juneau.swaggerui.path = docs}) to change the runtime mount without subclassing. 050 * Resolution happens once at {@link RestContext} construction time (SVL resolution in {@code @RestOp(path)}). 051 * 052 * <p> 053 * Override accepts bare token ({@code swagger}), leading slash ({@code /swagger}), trailing slash 054 * ({@code swagger/}), or wildcard suffix ({@code /swagger/*}) — all resolve to the same mount. 055 * 056 * <h5 class='section'>Mixin-only deployment:</h5> 057 * 058 * <p> 059 * This resource is designed for composition via {@code @Rest(mixins=...)}. The mount path is 060 * pinned at the op level by {@link RestGet @RestGet(path="/{juneau.swaggerui.path:swagger}/*")} 061 * on {@link #getSwaggerUi}; a class-level {@code @Rest(paths=...)} declaration would be silently 062 * ignored under the mixin pattern (see {@link Rest#paths() @Rest(paths)} Javadoc). 063 * 064 * <h5 class='figure'>Composition example:</h5> 065 * 066 * <p class='bjava'> 067 * <ja>@Rest</ja>(path=<js>"/myresource"</js>, mixins=SwaggerUiMixin.<jk>class</jk>) 068 * <jk>public class</jk> MyResource <jk>extends</jk> RestServlet { 069 * <jc>// Serves /myresource/api (transitively) and /myresource/swagger (this mixin).</jc> 070 * } 071 * </p> 072 * 073 * <h5 class='section'>Content negotiation:</h5> 074 * 075 * <p> 076 * The {@code @Rest(defaultAccept="text/html")} declaration causes bare browser requests 077 * (no {@code Accept} header) to render HTML via the {@link SwaggerUI} swap. 078 * Explicit accept headers (e.g. {@code Accept: application/json}) are honored normally. 079 * </p> 080 * 081 * <p> 082 * Sub-context inheritance confines the {@code defaultAccept} contribution to this 083 * mixin's endpoints — the host's other endpoints retain their own content-negotiation defaults. 084 * </p> 085 * 086 * <h5 class='section'>See Also:</h5><ul> 087 * <li class='jc'>{@link SwaggerMixin} 088 * <li class='jc'>{@link OpenApiMixin} 089 * <li class='jc'>{@link RedocMixin} 090 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerComposition">REST Server — Mixins and Multi-Mount Paths</a> 091 * </ul> 092 * 093 * @since 10.0.0 094 */ 095// @formatter:off 096@Rest( 097 mixins={SwaggerMixin.class}, 098 defaultAccept="text/html" 099) 100@JsonSchemaConfig( 101 addDescriptionsTo="bean,collection,array,map,enum", 102 addExamplesTo="bean,collection,array,map", 103 ignoreTypes="Swagger,org.apache.juneau.bean.html5.*", 104 useBeanDefs="true" 105) 106public class SwaggerUiMixin { 107 108 /** 109 * [GET /swagger] — render the Swagger-UI HTML view (or the spec, depending on {@code Accept}). 110 * 111 * @param req The current REST request. 112 * @return The Swagger document. 113 * @throws NotFound If no Swagger document is available for this resource. 114 */ 115 @RestGet( 116 path="/#{pathToken(${juneau.swaggerui.path:swagger})}/*", 117 summary="Swagger UI", 118 description="Swagger-UI HTML view of the Swagger v2 documentation for this resource." 119 ) 120 @HtmlDocConfig( 121 rank=10, 122 navlinks={ 123 "back: servlet:/", 124 "json: servlet:/swagger?Accept=text/json&plainText=true" 125 }, 126 aside="NONE" 127 ) 128 @MarshalledConfig( 129 swaps={ 130 SwaggerUI.class 131 } 132 ) 133 public Swagger getSwaggerUi(RestRequest req) { 134 return req.getSwagger().orElseThrow(NotFound::new); 135 } 136}