Raggett is an opinionated Go HTTP Server Framework
go get github.com/heyvito/raggett@v0.1.7
Raggett is built on top of Chi to provide
routing and middlewares; the way it handles requests and responses are the
main difference between the common way Go HTTP servers are built. Instead of
implementing handlers dealing with both http.Request
and
http.ResponseWriter
, the library encapsulates all common operations on a
single Request
object. The library also makes heavy usage of Zap
to provide logging facilities.
The following snippet represents a simple Raggett Application:
package main
import (
"fmt"
"net/http"
"github.com/heyvito/raggett"
"go.uber.org/zap"
)
type HelloRequest struct {
*raggett.Request
Name string `form:"name" required:"true" blank:"false"`
}
func main() {
mux := raggett.NewMux(zap.L())
// Handlers must be a function accepting a single struct that uses
// *raggett.Request as a promoted field, and returns an error.
mux.Post("/", func(r HelloRequest) error {
r.RespondString(fmt.Sprintf("Hello, %s!", r.Name))
return nil
})
http.ListenAndServe(":3000", mux)
}
The same application can also be extended to provide both HTML and plain text responses by implementing a structure implementing a set of interfaces provided by the library. For instance:
package main
import (
"fmt"
"net/http"
"github.com/heyvito/raggett"
"go.uber.org/zap"
)
type HelloRequest struct {
*raggett.Request
Name string `form:"name" required:"true" blank:"false"`
}
type HelloResponse struct {
Name string
}
func (h HelloResponse) JSON() interface{} {
return map[string]interface{}{
"greeting": fmt.Sprintf("Hello, %s!", h.Name),
}
}
func (h HelloResponse) HTML() string {
return fmt.Sprintf("<h1>Hello, %s!</h1>", h.Name)
}
func main() {
mux := raggett.NewMux(zap.L())
mux.Post("/", func(r HelloRequest) error {
r.Respond(HelloResponse{
Name: r.Name,
})
return nil
})
http.ListenAndServe(":3000", mux)
}
When defining a request object, form values can be automatically loaded and converted to specific types by using tags:
type SignUpRequest struct {
*raggett.Request
Name string `form:"name" required:"true" blank:"false"`
Email string `form:"email" pattern:"^.+@.+\..+$"`
SubscribeNewsletter bool `form:"subscribe"`
}
The same pattern used by forms can be applied to QueryString parameters:
type ListUsersRequest struct {
*raggett.Request
Page int `query:"page"`
}
As Raggett is built on top of Chi, URL parameters can also be accessed through fields defined on structs and marked with tags:
type ListPostsForDay struct {
*raggett.Request
Day int `url-param:"day"`
Month int `url-param:"month"`
Year int `url-param:"year"`
}
mux.Get("/blog/posts/{day}/{month}/{year}", func(r ListPostsForDay) error {
// ...
})
When not using Forms or Multipart requests, applications can also rely on JSON or XML being posted, for instance. For that, Raggett has a set of Resolvers that can be attached directly to a field indicating that the request's body must be parsed and set it:
type SignUpRequest struct {
*raggett.Request
UserData struct {
Email string `json:"email"`
Name string `json:"name"`
} `body:"json"`
}
Multipart data is also supported. To receive a single file:
type ExampleRequest struct {
*raggett.Request
Photo *raggett.FileHeader `form:"photo" required:"false"`
}
Or multiple files:
type ExampleRequest struct {
*raggett.Request
Photos []*raggett.FileHeader `form:"photo" required:"false"`
}
ProTip™:
raggett.FileHeader
is simply an alias to stdlib'smultipart.FileHeader
. Both types are interchangeable on Raggett.
Just like other values, headers can also be obtained through tags:
type AuthenticatedRequest struct {
*raggett.Request
Authorization string `header:"authorization" required:"true"`
}
Raggett provides default handlers for errors such as validation (HTTP 400),
runtime (HTTP 500), Not Found (HTTP 404), and Method Not Allowed (HTTP 405). For
those errors, the library is capable of responding to the following formats,
based on the Accept
header provided by the client:
- HTML
- JSON
- XML
- Plain Text
The library also provides a "Development" mode, which augments information provided by those error handlers:
mux := raggett.NewMux(...)
mux.Development = true
⚠️ Warning! Setting Development totrue
on production environments is unadvised, since it may cause sensitive information to be exposed to the internet.
The MIT License (MIT)
Copyright (c) 2021-2024 Vito Sartori
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.