Search code examples
apigoswagger-uigo-templatesapi-doc

When providing pregenerated links for supporting multiple API specs Swagger UI doesn't load the specs


I have a service written in Go that also uses go templates for frontend. This service is used by our external third parties as a portal for looking up stuff and searching. There is another service that is a rest API for handling orders. The portal service has a page where you can look up API docs. I had only one API version and I use SwaggerUI for showing API docs. I had to create a new endpoint and make it a part of a new API version. Now I want to show a new API version but also the old one for supporting old clients. Something like this: enter image description here

So when a user clicks a button on the portal website to see documentation, the request is handled by this function in portal (Note: I already refactored this function to support multiple urls):

func getDocs(c echo.Context) error {
    source := c.Get(auth.SourceName).(string)
    key := c.Get(auth.KeyName).(string)

    jsonURLs := []DocsURL{
        {
            url:         fmt.Sprintf("%s/0.1/docs?source=%s", config.baseURL, key),
            name:        "0.1"
        },
        {
            url:         fmt.Sprintf("%s/1.0/docs?source=%s", config.baseURL, key),
            name:        "0.1"
        },
    }

    return c.Render(http.StatusOK, "docs/index", map[string]interface{}{
        "source":   source,
        "key":      key,
        "pageType": "docs",
        "jsonURLs": jsonURLs,
    })
}

And this is the script from the template where I use SwaggerUI:

  window.onload = function() {
    const ui = SwaggerUIBundle({
      urls: {{ .jsonURLs }},
      dom_id: '#swagger-ui',
      deepLinking: true,
      presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIStandalonePreset
      ],
      plugins: [
        SwaggerUIBundle.plugins.DownloadUrl
      ],
      layout: "StandaloneLayout",
      supportedSubmitMethods: []
    })
    window.ui = ui
    $('.tryitout').prop('disabled', true);
  }

I need to generate links depending on the environment (production, staging, local). Also it makes sense to generate data on the backend and feed it to the template to display. BUT THIS DOENS'T WORK!

However, if I hard-code the links in the SwaggerUIBundle it works and portal shows a correct drop-down menu and allows to switch between versions and loads docs for the corresponding version.

func getDocs(c echo.Context) error {
    source := c.Get(auth.SourceName).(string)
    key := c.Get(auth.KeyName).(string)

    return c.Render(http.StatusOK, "docs/index", map[string]interface{}{
        "source":   source,
        "key":      key,
        "pageType": "docs",
    })
}

In the template:

window.onload = function() {
    const ui = SwaggerUIBundle({
      urls: [
        {
          url: "http://localhost:8088/0.1/docs?source=111111",
          name: "0.1"
        },
        {
          url: "http://localhost:8088/1.0/docs?source=111111",
          name: "1.0"
        }
      ],
      dom_id: '#swagger-ui',
      deepLinking: true,
      presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIStandalonePreset
      ],
      plugins: [
        SwaggerUIBundle.plugins.DownloadUrl
      ],
      layout: "StandaloneLayout",
      supportedSubmitMethods: []
    })
    window.ui = ui
    $('.tryitout').prop('disabled', true);
  }

Why is that? And is there a way to make the first version of code work?

I need the links to be dynamic and preferably generated in the handler. Thank you!


Solution

  • There appear to be two mistakes:

    First:

      urls: {{ .jsonURLs }},
    

    This will not write jsonURLs in JSON format for you. It will simply write a string representation of jsonURLs. Either you need to write the template to iterate elements of jsonURLs and print them out one by one, or marshal jsonURLs to json yourself:

    jsonText,_:=json.Marshal(jsonURLs)
    return c.Render(http.StatusOK, "docs/index", map[string]interface{}{
            "source":   source,
            "key":      key,
            "pageType": "docs",
            "jsonURLs": string(jsonText),
        })
    

    Second: it looks like you didn't export the member fields of DocsURL struct. Capitalize the field names and add json tags.

    type DocsURL struct {
      URL string `json:"url"`
      Name string `json:"name"`
    }