provide^Wupdate docs of package web
continuous-integration/drone the build is pending Details

This commit is contained in:
Lennart 2021-07-19 17:59:47 +02:00 committed by Geno
parent 6af94245b6
commit b10fc5b588
6 changed files with 46 additions and 36 deletions

View File

@ -1,6 +1,6 @@
package web package web
// HTTPError as a response, with data // HTTPError is returned in HTTP error responses.
type HTTPError struct { type HTTPError struct {
Message string `json:"message" example:"invalid format"` Message string `json:"message" example:"invalid format"`
Error string `json:"error,omitempty" example:"<internal error message>"` Error string `json:"error,omitempty" example:"<internal error message>"`
@ -8,10 +8,7 @@ type HTTPError struct {
} }
const ( const (
// APIErrorInvalidRequestFormat const for api error with invalid request format
APIErrorInvalidRequestFormat = "Invalid Request Format" APIErrorInvalidRequestFormat = "Invalid Request Format"
// APIErrorInternalDatabase const for api error with problem with database
APIErrorInternalDatabase = "Internal Database Error" APIErrorInternalDatabase = "Internal Database Error"
// APIErrorNotFound const for api error with not found object
APIErrorNotFound = "Not found" APIErrorNotFound = "Not found"
) )

View File

@ -1,3 +1,12 @@
/*
Package web implements common functionality for web APIs using Gin and Gorm.
Modules
Modules provide functionality for a web server. A module is a function executed
before starting a server, accessing the Service and the Gin Engine. Each Service
maintains a list of modules. When it runs, it executes all of its modules.
*/
package web package web
import ( import (
@ -13,8 +22,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// Service to store Configuration and Webserver wide objects // A Service stores configuration of a server.
// (like DB Connection)
type Service struct { type Service struct {
// config // config
Listen string `toml:"listen"` Listen string `toml:"listen"`
@ -36,32 +44,32 @@ type Service struct {
modules []ModuleRegisterFunc modules []ModuleRegisterFunc
} }
// Run to startup all related web parts // Run creates, configures, and runs a new gin.Engine using its registered
// (e.g. configure the server, metrics, and finally bind routing) // modules.
func (config *Service) Run() error { func (s *Service) Run() error {
gin.EnableJsonDecoderDisallowUnknownFields() gin.EnableJsonDecoderDisallowUnknownFields()
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
r := gin.New() r := gin.New()
// catch crashed // catch crashed
r.Use(gin.Recovery()) r.Use(gin.Recovery())
if config.AccessLog { if s.AccessLog {
r.Use(gin.Logger()) r.Use(gin.Logger())
log.Debug("request logging enabled") log.Debug("request logging enabled")
} }
config.LoadSession(r) s.LoadSession(r)
config.Bind(r) s.Bind(r)
if config.ACME.Enable { if s.ACME.Enable {
if config.Listen != "" { if s.Listen != "" {
log.Panic("For ACME / Let's Encrypt it is not possible to set `listen`") log.Panic("For ACME / Let's Encrypt it is not possible to set `listen`")
} }
m := autocert.Manager{ m := autocert.Manager{
Prompt: autocert.AcceptTOS, Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(config.ACME.Domains...), HostPolicy: autocert.HostWhitelist(s.ACME.Domains...),
Cache: autocert.DirCache(config.ACME.Cache), Cache: autocert.DirCache(s.ACME.Cache),
} }
return autotls.RunWithManager(r, &m) return autotls.RunWithManager(r, &m)
} }
return r.Run(config.Listen) return r.Run(s.Listen)
} }

View File

@ -6,15 +6,15 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// ModuleRegisterFunc format of module which registered to WebService // A ModuleRegisterFunc is a module.
type ModuleRegisterFunc func(*gin.Engine, *Service) type ModuleRegisterFunc func(*gin.Engine, *Service)
// ModuleRegister used on start of WebService // ModuleRegister adds f to ws's list of modules.
func (ws *Service) ModuleRegister(f ModuleRegisterFunc) { func (ws *Service) ModuleRegister(f ModuleRegisterFunc) {
ws.modules = append(ws.modules, f) ws.modules = append(ws.modules, f)
} }
// Bind WebService to gin.Engine // Bind executes all of ws's modules with r.
func (ws *Service) Bind(r *gin.Engine) { func (ws *Service) Bind(r *gin.Engine) {
for _, f := range ws.modules { for _, f := range ws.modules {
f(r, ws) f(r, ws)

View File

@ -6,9 +6,11 @@ import (
"time" "time"
) )
// JSONRequest easy get request for json // JSONRequest issues a GET request to the specified URL and reads the returned
// JSON into value. See json.Unmarshal for the rules for converting JSON into a
// value.
func JSONRequest(url string, value interface{}) error { func JSONRequest(url string, value interface{}) error {
var netClient = &http.Client{ netClient := &http.Client{
Timeout: time.Second * 20, Timeout: time.Second * 20,
} }
@ -18,6 +20,7 @@ func JSONRequest(url string, value interface{}) error {
} }
err = json.NewDecoder(resp.Body).Decode(&value) err = json.NewDecoder(resp.Body).Decode(&value)
resp.Body.Close()
if err != nil { if err != nil {
return err return err
} }

View File

@ -5,19 +5,21 @@ import (
) )
const ( const (
// ContentTypeJSON content type of json
ContentTypeJSON = "application/json" ContentTypeJSON = "application/json"
// ContentTypeJS content type of javascript
ContentTypeJS = "application/javascript" ContentTypeJS = "application/javascript"
// ContentTypeXML content type of xml
ContentTypeXML = "text/xml" ContentTypeXML = "text/xml"
// ContentTypeYAML content type of yaml
ContentTypeYAML = "text/yaml" ContentTypeYAML = "text/yaml"
// ContentTypeHTML content type of html
ContentTypeHTML = "text/html" ContentTypeHTML = "text/html"
) )
// Response give // Response sends an HTTP response.
//
// statusCode is the respone's status.
//
// If the request's Content-Type is JavaScript, JSON, YAML, or XML, it returns
// data serialized as JSONP, JSON, YAML, or XML, respectively. If the
// Content-Type is HTML, it returns the HTML template templateName rendered with
// data.
func Response(ctx *gin.Context, statusCode int, data interface{}, templateName string) { func Response(ctx *gin.Context, statusCode int, data interface{}, templateName string) {
switch ctx.ContentType() { switch ctx.ContentType() {
case ContentTypeJS: case ContentTypeJS:

View File

@ -6,8 +6,8 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// LoadSession module to start Session Handling in WebService // LoadSessions starts session handling for s.
func (config *Service) LoadSession(r *gin.Engine) { func (s *Service) LoadSession(r *gin.Engine) {
store := cookie.NewStore([]byte(config.Session.Secret)) store := cookie.NewStore([]byte(s.Session.Secret))
r.Use(sessions.Sessions(config.Session.Name, store)) r.Use(sessions.Sessions(s.Session.Name, store))
} }