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}} &mdash; 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/*}) &mdash; 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="/&#123;juneau.swagger.path:api&#125;/*")} 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&lt;Item&gt; 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}