Documentation ¶
Index ¶
- Variables
- func DEBUG(ctx context.Context, msg string, args ...any)
- func ERROR(ctx context.Context, msg string, args ...any)
- func Error(code int, err error) error
- func INFO(ctx context.Context, msg string, args ...any)
- func WARN(ctx context.Context, msg string, args ...any)
- type BindError
- type BindErrors
- type BindFunc
- type BindParam
- type BindSource
- type Codec
- type Codecs
- type Context
- type ContextExtender
- type Endpoint
- type EndpointBuilder
- type Espresso
- type HTTPError
- type HandleFunc
- type JSON
- type MiddlewareProvider
- type Router
- type YAML
Examples ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( CodecsModule = module.New[*Codecs]() ProvideCodecs = CodecsModule.ProvideWithFunc(func(context.Context) (*Codecs, error) { return NewCodecs(JSON{}, YAML{}), nil }) )
View Source
var ( LogModule = module.New[*slog.Logger]() LogText = LogModule.ProvideWithFunc(func(ctx context.Context) (*slog.Logger, error) { handler := slog.NewTextHandler(os.Stderr, nil) return slog.New(handler), nil }) LogJSON = LogModule.ProvideWithFunc(func(ctx context.Context) (*slog.Logger, error) { handler := slog.NewJSONHandler(os.Stderr, nil) return slog.New(handler), nil }) )
Functions ¶
Types ¶
type BindError ¶ added in v0.3.1
type BindError struct { Key string From BindSource Type reflect.Type Err error }
BindError describes the error when binding a param.
type BindErrors ¶ added in v0.3.1
type BindErrors []BindError
BindErrors describes all errors when binding params.
func (BindErrors) Error ¶ added in v0.3.1
func (e BindErrors) Error() string
func (BindErrors) Unwrap ¶ added in v0.3.1
func (e BindErrors) Unwrap() []error
type BindParam ¶ added in v0.4.0
type BindParam struct { Key string From BindSource Type reflect.Type Func BindFunc }
type BindSource ¶ added in v0.6.0
type BindSource int
BindSource describes the type of bind.
const ( BindPathParam BindSource = iota BindFormParam BindQueryParam BindHeadParam )
func (BindSource) String ¶ added in v0.6.0
func (b BindSource) String() string
func (BindSource) Valid ¶ added in v0.6.0
func (b BindSource) Valid() bool
type Codecs ¶ added in v0.6.0
type Codecs struct {
// contains filtered or unexported fields
}
func (*Codecs) DecodeRequest ¶ added in v0.6.0
func (*Codecs) EncodeResponse ¶ added in v0.6.0
type Context ¶
type Context interface { context.Context ContextExtender Endpoint(method string, path string, middlewares ...HandleFunc) EndpointBuilder Next() Request() *http.Request ResponseWriter() http.ResponseWriter }
type ContextExtender ¶ added in v0.6.0
type EndpointBuilder ¶ added in v0.4.0
type EndpointBuilder interface { BindPath(key string, v any) EndpointBuilder End() BindErrors }
type Espresso ¶ added in v0.6.0
type Espresso struct {
// contains filtered or unexported fields
}
Example ¶
type Book struct { ID int `json:"id"` Title string `json:"title"` } type Books map[int]Book books := make(Books) books[1] = Book{ ID: 1, Title: "The Espresso Book", } books[2] = Book{ ID: 2, Title: "The Second Book", } espo := espresso.New() // Log to stdout for Output espo.AddModule(espresso.LogModule.ProvideWithFunc(func(ctx context.Context) (*slog.Logger, error) { removeTime := func(groups []string, a slog.Attr) slog.Attr { // Remove time from the output for predictable test output. if a.Key == slog.TimeKey { return slog.Attr{} } return a } opt := slog.HandlerOptions{ ReplaceAttr: removeTime, } return slog.New(slog.NewTextHandler(os.Stdout, &opt)), nil })) espo.AddModule(espresso.ProvideCodecs) router := espo.WithPrefix("/http") router.HandleFunc(func(ctx espresso.Context) error { var id int if err := ctx.Endpoint(http.MethodGet, "/book/{id}"). BindPath("id", &id). End(); err != nil { return err } book, ok := books[id] if !ok { return espresso.Error(http.StatusNotFound, fmt.Errorf("not found")) } if err := espresso.CodecsModule.Value(ctx).EncodeResponse(ctx, &book); err != nil { return err } return nil }) router.HandleFunc(func(ctx espresso.Context) error { if err := ctx.Endpoint(http.MethodPost, "/book"). End(); err != nil { return err } codecs := espresso.CodecsModule.Value(ctx) var book Book if err := codecs.DecodeRequest(ctx, &book); err != nil { return espresso.Error(http.StatusBadRequest, err) } book.ID = len(books) books[book.ID] = book if err := codecs.EncodeResponse(ctx, &book); err != nil { return err } return nil }) svr := httptest.NewServer(espo) defer svr.Close() func() { var book Book resp, err := http.Get(svr.URL + "/http/book/1") if err != nil { panic(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { panic(resp.Status) } if err := json.NewDecoder(resp.Body).Decode(&book); err != nil { panic(err) } fmt.Println("Book 1 title:", book.Title) }() func() { arg := Book{Title: "The New Book"} var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(&arg); err != nil { panic(err) } resp, err := http.Post(svr.URL+"/http/book", "application/json", &buf) if err != nil { panic(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { panic(resp.Status) } var ret Book if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil { panic(err) } fmt.Println("The New Book id:", ret.ID) }()
Output: level=INFO msg="receive http" method=GET path=/http/book/1 level=INFO msg="finish http" method=GET path=/http/book/1 Book 1 title: The Espresso Book level=INFO msg="receive http" method=POST path=/http/book level=INFO msg="finish http" method=POST path=/http/book The New Book id: 2
Example (Rpc) ¶
type Book struct { ID int `json:"id"` Title string `json:"title"` } type Books map[int]Book books := make(Books) books[1] = Book{ ID: 1, Title: "The Espresso Book", } books[2] = Book{ ID: 2, Title: "The Second Book", } espo := espresso.New() // Log to stdout for Output espo.AddModule(espresso.LogModule.ProvideWithFunc(func(ctx context.Context) (*slog.Logger, error) { removeTime := func(groups []string, a slog.Attr) slog.Attr { // Remove time from the output for predictable test output. if a.Key == slog.TimeKey { return slog.Attr{} } return a } opt := slog.HandlerOptions{ ReplaceAttr: removeTime, } return slog.New(slog.NewTextHandler(os.Stdout, &opt)), nil })) espo.AddModule(espresso.ProvideCodecs) router := espo.WithPrefix("/rpc") router.HandleFunc(espresso.RPCRetrive(func(ctx espresso.Context) (*Book, error) { var id int if err := ctx.Endpoint(http.MethodGet, "/book/{id}"). BindPath("id", &id). End(); err != nil { return nil, err } book, ok := books[id] if !ok { return nil, espresso.Error(http.StatusNotFound, fmt.Errorf("not found")) } return &book, nil })) router.HandleFunc(espresso.RPC(func(ctx espresso.Context, book *Book) (*Book, error) { if err := ctx.Endpoint(http.MethodPost, "/book"). End(); err != nil { return nil, err } book.ID = len(books) books[book.ID] = *book return book, nil })) svr := httptest.NewServer(espo) defer svr.Close() func() { var book Book resp, err := http.Get(svr.URL + "/rpc/book/1") if err != nil { panic(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { panic(resp.Status) } if err := json.NewDecoder(resp.Body).Decode(&book); err != nil { panic(err) } fmt.Println("Book 1 title:", book.Title) }() func() { arg := Book{Title: "The New Book"} var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(&arg); err != nil { panic(err) } resp, err := http.Post(svr.URL+"/rpc/book", "application/json", &buf) if err != nil { panic(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { panic(resp.Status) } var ret Book if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil { panic(err) } fmt.Println("The New Book id:", ret.ID) }()
Output: level=INFO msg="receive http" method=GET path=/rpc/book/1 level=INFO msg="finish http" method=GET path=/rpc/book/1 Book 1 title: The Espresso Book level=INFO msg="receive http" method=POST path=/rpc/book level=INFO msg="finish http" method=POST path=/rpc/book The New Book id: 2
func (*Espresso) HandleFunc ¶ added in v0.6.0
func (s *Espresso) HandleFunc(handleFunc HandleFunc)
func (*Espresso) ServeHTTP ¶ added in v0.6.0
func (s *Espresso) ServeHTTP(w http.ResponseWriter, r *http.Request)
func (*Espresso) Use ¶ added in v0.6.0
func (s *Espresso) Use(middlewares ...HandleFunc)
func (*Espresso) WithPrefix ¶ added in v0.6.0
type HandleFunc ¶ added in v0.4.0
func RPC ¶ added in v0.6.0
func RPC[Request, Response any](fn func(Context, Request) (Response, error)) HandleFunc
func RPCConsume ¶ added in v0.6.0
func RPCConsume[Request any](fn func(Context, Request) error) HandleFunc
func RPCRetrive ¶ added in v0.6.0
func RPCRetrive[Response any](fn func(Context) (Response, error)) HandleFunc
type JSON ¶ added in v0.6.0
type JSON struct{}
type MiddlewareProvider ¶ added in v0.6.0
type MiddlewareProvider interface {
Middlewares() []HandleFunc
}
type Router ¶ added in v0.3.1
type Router interface { Use(middlewares ...HandleFunc) WithPrefix(path string) Router HandleFunc(handleFunc HandleFunc) }
Source Files ¶
Click to show internal directories.
Click to hide internal directories.