Otto is an easy way to use HTTP in golang. You can either use the Otto App with features like gracefully shutdown on OS signals interrupt and kill, or just use the Otto Router and handle the HTTP Server as you like!
Otto uses Gorilla/mux to define routes.
- Group APIs
- Middleware
- Functions that makes it easy to send HTTP responses
- Centralized HTTP error handling
- Custom error handlers to specific HTTP status codes
- Possibility to only use the router part
- A easy way to decode the request body (only json for now, other formats will come later)
- Automatic TLS via Let’s Encrypt
Example of how to use the Otto App
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
opts := otto.NewOptions()
opts.Addr = ":3000"
app := otto.New(opts)
app.GET("/", func(ctx otto.Context) error {
return ctx.String(200, "Hello world!")
})
log.Fatal(app.Serve())
}
Example of how to use Otto with TLS
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
opts := otto.NewOptions()
opts.Addr = ":443"
app := otto.New(opts)
if err := app.UseTLS("path/to/cert", "path/to/key"); err != nil {
log.Fatal(err)
}
app.GET("/", func(ctx otto.Context) error {
return ctx.String(200, "Hello world!")
})
log.Fatal(app.Serve())
}
Example of how to use Otto with Auto TLS from Let’s Encrypt
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
opts := otto.NewOptions()
opts.Addr = ":443"
app := otto.New(opts)
app.UseAutoTLS(autocert.DirCache("/path/to/cache"))
app.GET("/", func(ctx otto.Context) error {
return ctx.String(200, "Hello world!")
})
log.Fatal(app.Serve())
}
Example of how to use the Router without the Otto App.
The Router implements the http.Handler
so it is easy to use without the App
!
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
r := otto.NewRouter(false)
r.GET("/", func(ctx otto.Context) error {
return ctx.String(200, "Hello world!")
})
log.Fatal(http.ListenAndServe(":3000", r))
}
Example of using middlewares
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
r := otto.NewRouter(false)
r.Use(func(next otto.HandlerFunc) otto.HandlerFunc {
return func(ctx otto.Context) error {
ctx.Set("some key", "I'm a middleware!")
return next(ctx)
}
})
r.GET("/", func(ctx otto.Context) error {
return ctx.String(200, "Hello world!")
})
log.Fatal(http.ListenAndServe(":3000", r))
}
Example of how to associate error handler to HTTP status code
package main
import (
"log"
"github.com/JacobSoderblom/otto"
)
func main() {
r := otto.NewRouter(false)
errorHandlers := map[int]otto.ErrorHandler{
400: func(code int, err error, ctx otto.Context) error {
// do some awesome error handling!
return ctx.Error(code, err)
},
401: func(code int, err error, ctx otto.Context) error {
// do some awesome error handling!
return ctx.Error(code, err)
},
}
r.SetErrorHandlers(errorHandlers)
r.GET("/", func(ctx otto.Context) error {
return ctx.String(400, "Hello world!")
})
log.Fatal(http.ListenAndServe(":3000", r))
}
Example of how to decode the request body
package main
import (
"fmt"
"log"
"net/http"
"github.com/JacobSoderblom/otto"
)
func main() {
r := otto.NewRouter(false)
r.POST("/", func(ctx otto.Context) error {
var body struct {
Msg string `json:"msg"`
}
if err := ctx.Bind(&body); err != nil {
return err
}
return ctx.JSON(200, body)
})
log.Fatal(http.ListenAndServe(":3000", r))
}