jdaugherty commented on issue #11276:
URL: https://github.com/apache/grails-core/issues/11276#issuecomment-3782628302

   I recently answered how to accomplish this in the Grails slack chat, and 
thought I would preserve the answer by adding it here: 
   
   We check in a file at the root of our project called: 
   
   openapi.yaml
   
    This file contains all of the app info since we don't use the annotations 
on the application, etc (only controllers and associated components), so 
something like this:
   
        #file: noinspection YAMLSchemaValidation
        openapi: 3.0.1
        info:
          title: My API Name
          description: |
            Markdown syntax here to describe your API
        
          version: API_VERSION
          x-logo:
            url: URL Logo
            href: URL Website
        servers:
          - url: example link to your api
            description: Production API
            variables: {}
        security:
          - Bearer: []
        # use use x-tagGroups: & tags: since we use redoc to render our api spec
        components:
          securitySchemes:
            Bearer:
              type: http
              description: description of your security scheme, any caveats
              scheme: bearer
              bearerFormat: JWT
   
   
   Then in our gradle file:
   
   
         plugins {
               id "io.swagger.core.v3.swagger-gradle-plugin"
         }
   
         tasks.register('updateOpenAPIVersion', Copy) {
            from "openapi.yaml"
            into "$buildDir/tmp"
            filter { line -> line.replaceAll('API_VERSION', project.version) }
        }
        
        // Generates api spec that we serve up via redoc
        // However, you can also generate static documentation, install the 
redoc-cli via 'npm i -g redoc-cli'
        // Run 'gradle resolve' and then 'redoc-cli build 
build/resources/main/openapi/my-api-name.yaml -o build/my-api-name.html'
        //
        resolve {
            dependsOn(tasks.updateOpenAPIVersion, classes)
            classpath = sourceSets.main.runtimeClasspath
            outputDir = file("$buildDir/resources/main/openapi")
            outputFileName = 'my-api-name.yaml'
            openApiFile = file("$buildDir/tmp/openapi.yaml")
            outputFormat = 'YAML'
            resourcePackages = ['com.example'] # packages to search for the 
annotations
            readAllResources = false
            prettyPrint = true
        }
        
        bootJarMainClassName {
            dependsOn(resolve)
        }
        
        dependencies {
            // other dependencies
        
            implementation "io.swagger.core.v3swagger 
annotations${swaggerVersion}"
            implementation "javax.ws.rs:javax.ws.rs-api:2.1.1"
        }
   
   
   we also add a doc controller:
   
   
        @Secured(AuthenticatedVoter.IS_AUTHENTICATED_ANONYMOUSLY)
        class RedocController {
            def index() {
                Resource redocHtml = 
ApplicationContextHolder.applicationContext.getResource("classpath:redoc/index.html")
                try(InputStreamReader reader = new 
InputStreamReader(redocHtml.inputStream)) {
                    render(text: reader.text, contentType: "text/html", 
encoding: "UTF-8")
                }
            }
        
            def definition() {
                Resource apiYaml = 
ApplicationContextHolder.applicationContext.getResource("classpath:openapi/my-api-name.yaml")
                try(InputStreamReader reader = new 
InputStreamReader(apiYaml.inputStream)) {
                    render(text: reader.text, contentType: 
"application/x-yaml", encoding: "UTF-8")
                }
            }
        }
   
   
   with a index.html similar to this:
   
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <title>My API Name | API Reference</title>
            <!-- needed for adaptive design -->
            <meta charset='UTF-8'/>
            <meta name='viewport' content='width=device-width, 
initial-scale=1'/>
            <!-- prevent IE from caching this page -->
            <meta http-equiv="Cache-Control" content="no-store"/>
            <meta http-equiv="Pragma" content="no-cache">
            <meta http-equiv="Expires" content="-1">
            <!-- force this page to be rendered with the latest version of IE 
-->
            <meta http-equiv="x-ua-compatible" content="IE=edge">
            <meta name="layout" content="none"/>
            <link 
href='https://fonts.googleapis.com/css?family=Montserrat:300,400,700%7CRoboto:300,400,700'
 rel='stylesheet'/>
        
            <!-- ReDoc doesn't change outer page styles -->
            <style>
            body {
                margin: 0;
                padding: 0;
            }
            </style>
        </head>
        
        <body>
        <redoc spec-url='/definition' path-in-middle-panel="true" 
expand-responses="all" showObjectSchemaExamples="true" 
showExtensions="true"></redoc>
        <script 
src='https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js'></script>
        </body>
        </html>
   
   
   
   so to recap: use the resolve task to generate the api documentation, in our 
case we define some of it statically and merge it, use a controller to service 
the spec, and use an action to serve redocly to render the spec so it's 
interactive


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to