# HG changeset patch
# User Christophe de Vienne <christophe@cdevienne.info>
# Date 1600271183 -7200
#      Wed Sep 16 17:46:23 2020 +0200
# Node ID 671a59428de96f412315d30d5daf775046735464
# Parent  986bea85afd6abd0979fbdc3d10a40f6d80ac80b
Add the redoc middleware

diff --git a/redoc.go b/redoc.go
new file mode 100644
--- /dev/null
+++ b/redoc.go
@@ -0,0 +1,102 @@
+package orusapi
+
+import (
+	"bytes"
+	"fmt"
+	"html/template"
+	"net/http"
+	"path"
+)
+
+// RedocOpts configures the Redoc middleware
+type RedocOpts struct {
+	// BasePath for the UI path, defaults to: /
+	BasePath string
+	// Path combines with BasePath for the full UI path, defaults to: docs
+	Path string
+	// SpecURL the url to find the spec for
+	SpecURL string
+	// RedocURL for the js that generates the redoc site, defaults to: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js
+	RedocURL string
+	// Title for the documentation site, default to: API documentation
+	Title string
+}
+
+// EnsureDefaults in case some options are missing
+func (r *RedocOpts) EnsureDefaults() {
+	if r.BasePath == "" {
+		r.BasePath = "/"
+	}
+	if r.Path == "" {
+		r.Path = "docs"
+	}
+	if r.SpecURL == "" {
+		r.SpecURL = "/swagger.json"
+	}
+	if r.RedocURL == "" {
+		r.RedocURL = redocLatest
+	}
+	if r.Title == "" {
+		r.Title = "API documentation"
+	}
+}
+
+// Redoc creates a middleware to serve a documentation site for a swagger spec.
+// This allows for altering the spec before starting the http listener.
+//
+func Redoc(opts RedocOpts) func(http.Handler) http.Handler {
+	opts.EnsureDefaults()
+
+	pth := path.Join(opts.BasePath, opts.Path)
+	tmpl := template.Must(template.New("redoc").Parse(redocTemplate))
+
+	buf := bytes.NewBuffer(nil)
+	_ = tmpl.Execute(buf, opts)
+	b := buf.Bytes()
+
+	return func(next http.Handler) http.Handler {
+		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+			if r.URL.Path == pth {
+				rw.Header().Set("Content-Type", "text/html; charset=utf-8")
+				rw.WriteHeader(http.StatusOK)
+
+				_, _ = rw.Write(b)
+				return
+			}
+
+			if next == nil {
+				rw.Header().Set("Content-Type", "text/plain")
+				rw.WriteHeader(http.StatusNotFound)
+				_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
+				return
+			}
+			next.ServeHTTP(rw, r)
+		})
+	}
+}
+
+const (
+	redocLatest   = "https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"
+	redocTemplate = `<!DOCTYPE html>
+<html>
+  <head>
+    <title>{{ .Title }}</title>
+    <!-- needed for adaptive design -->
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!--
+    ReDoc doesn't change outer page styles
+    -->
+    <style>
+      body {
+        margin: 0;
+        padding: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <redoc spec-url='{{ .SpecURL }}'></redoc>
+    <script src="{{ .RedocURL }}"> </script>
+  </body>
+</html>
+`
+)