Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,15 @@ f.GET("/openapi.json", nil, f.OpenAPI(infos, "json"))
```
**NOTE**: The generator will never panic. However, it is strongly recommended to call `fizz.Errors` to retrieve and handle the errors that may have occured during the generation of the specification before starting your API.

## Swagger UI
To serve Swagger UI for generated Open API specification, use `AddOpenApiUIHandler` method specifying the path
``` go
f.GET("/openapi.json", nil, f.OpenAPI(infos, "json"))
swagger.AddOpenApiUIHandler(f.Engine(),"swagger-ui", "/openapi.json" )
```
Swagger UI will be available at `/swagger-ui` using json from `/openapi.json`


#### Components

The output types of your handlers are registered as components within the generated specification. By default, the name used for each component is composed of the package and type name concatenated using _CamelCase_ style, and does not contain the full import path. As such, please ensure that you don't use the same type name in two eponym package in your application.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/wI2L/fizz

go 1.12
go 1.16

require (
github.com/Pallinder/go-randomdata v1.2.0
Expand Down
95 changes: 95 additions & 0 deletions swagger/fs_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package swagger

import (
"bytes"
"html/template"
"io"
"io/fs"
Comment thread
DenisPalnitsky marked this conversation as resolved.
"strings"
"time"
)

type fsWrapper struct {
fs fs.FS
jsonFileName string
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
}

func FsWrapper(fs fs.FS, jsonFilePath string) *fsWrapper {
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
return &fsWrapper{
fs: fs,
jsonFileName: jsonFilePath,
}
}

func (f *fsWrapper) Open(name string) (fs.File, error) {
if strings.HasSuffix(name, "index.html") {
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
tpl, err := template.ParseFS(f.fs, "index.gohtml")
if err != nil {
return nil, err
}
data := map[string]interface{}{
"openApiJson": strings.TrimPrefix(f.jsonFileName, "/"),
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
}

buf := new(bytes.Buffer)
if err = tpl.Execute(buf, data); err != nil {
return nil, err
}

return fsWrapperFile{
r: io.NopCloser(bytes.NewReader(buf.Bytes())),
fInfo: fileInfoMock{
name: name,
size: int64(buf.Len()),
},
}, nil
}

return f.fs.Open(name)
}

type fsWrapperFile struct {
r io.ReadCloser
fInfo fs.FileInfo
}

func (f fsWrapperFile) Stat() (fs.FileInfo, error) {
return f.fInfo, nil
}

func (f fsWrapperFile) Read(bytes []byte) (int, error) {
return f.r.Read(bytes)
}

func (f fsWrapperFile) Close() error {
return f.r.Close()
}

type fileInfoMock struct {
name string
size int64
}

func (f fileInfoMock) Name() string {
return f.name
}

func (f fileInfoMock) Size() int64 {
return f.size
}

func (f fileInfoMock) Mode() fs.FileMode {
return fs.FileMode(0)
}

func (f fileInfoMock) ModTime() time.Time {
return time.Now()
}

func (f fileInfoMock) IsDir() bool {
return false
}

func (f fileInfoMock) Sys() interface{} {
panic("implement me")
}
Binary file added swagger/swagger-ui/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added swagger/swagger-ui/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions swagger/swagger-ui/index.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="swagger-ui.css" />
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*,
*:before,
*:after
{
box-sizing: inherit;
}

body
{
margin:0;
background: #fafafa;
}
</style>
</head>

<body>
<div id="swagger-ui"></div>

<script src="swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/{{ .openApiJson }}",
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
// End Swagger UI call region

window.ui = ui;
};
</script>
</body>
</html>
75 changes: 75 additions & 0 deletions swagger/swagger-ui/oauth2-redirect.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;

if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}

arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};

isValid = qp.state === sentState;

if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}

if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}

oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}

window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions swagger/swagger-ui/swagger-ui-bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui-bundle.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions swagger/swagger-ui/swagger-ui-es-bundle-core.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui-es-bundle-core.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions swagger/swagger-ui/swagger-ui-es-bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui-es-bundle.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions swagger/swagger-ui/swagger-ui-standalone-preset.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui-standalone-preset.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions swagger/swagger-ui/swagger-ui.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui.css.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions swagger/swagger-ui/swagger-ui.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions swagger/swagger-ui/swagger-ui.js.map

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions swagger/swagger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package swagger

import (
"embed"
"github.com/gin-gonic/gin"
"io/fs"
"net/http"
)

//go:embed swagger-ui
var swaggerUiRes embed.FS

// AddUIHandler adds handler that serves html for Swagger UI
func AddUIHandler(ginEngine *gin.Engine, path string, openApiJsonPath string) {
sub, err := fs.Sub(swaggerUiRes, "swagger-ui")
if err != nil {
panic(err)
Comment thread
DenisPalnitsky marked this conversation as resolved.
Outdated
}

ginEngine.StaticFS(path, http.FS(FsWrapper(sub, openApiJsonPath)))
}