handler

package
v1.1.25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 12, 2024 License: MIT Imports: 10 Imported by: 1

README

HTTP handler

Package to make wrapped calls to HTTP endpoints. You can use it in service handlers.

Examples

Default

service.go:

type Service interface {
	CreateUser(http.ResponseWriter, *http.Request)
	Files(w http.ResponseWriter, r *http.Request)
}

type service struct {
	log  *logger.SLogger
	repo *repository.Repository
}

func New(log *logger.SLogger, repo *repository.Repository) Service {
	return &service{
		log:  log,
		repo: repo,
	}
}

// Parsing JSON body and binding it to CreateUserParams struct.
func (s *service) CreateUser(w http.ResponseWriter, r *http.Request) {
	handler.New(w, r, s.log, s.repo.CreateUser).
		WithJson().
		Run(http.StatusOK)
}

// Parsing multipart form and binding it to FilesParams struct.
func (s *service) Files(w http.ResponseWriter, r *http.Request) {
	handler.New(w, r, s.log, s.repo.Files).
		WithMultipart(32 << 20).
		Run(http.StatusOK)
}
Extract data from multiple sources

Sometimes you should extract variables from query and router vars(gorilla/mux).

For example: you have router to get users from a specific users group /users/{group_id} with limit and offset query params. You want to parse all this stuff and pass to your service method:

type UsersRequest struct {
  Limit   int `mapstructure:"limit"`
  Offset  int `mapstructure:"offset"`
  GroupID int `mapstructure:"group_id"`
}

func (r *Repository) GetGroupUsers(ctx context.Context, req *UsersRequest) ([]User, tiny_errors.ErrorHandler) {
  // ...

  return users, nil
}

// ...

// GetGroupUsers have request type *UsersRequest 
func (s *service) GetGroupUsers(w http.ResponseWriter, r *http.Request) {
	handler.New(w, r, s.log, s.repo.GetGroupUsers).WithQuery().WithVars().Run(http.StatusOK)
}

Or maybe you should extract router-vars and parse JSON-data from request body:

type CreateGroupUserRequest struct {
  Name string `json:"name"`
  Description string `json:"description"`
  Avatar string `json:"avatar"`
  GroupID int `mapstructure:"group_id"`
}

func (r *Repository) CreateGroupUser(ctx context.Context, req *CreateGroupUserRequest) (User, tiny_errors.ErrorHandler) {
  // ...

  return newUser, nil
}

// ...

// CreateGroupUser have request type *CreateGroupUserRequest 
func (s *service) CreateGroupUser(w http.ResponseWriter, r *http.Request) {
	handler.New(w, r, s.log, s.repo.GetGroupUsers).WithVars().WithJSON().Run(http.StatusCreated)
}

Documentation

Index

Constants

View Source
const (
	ErrNotValidBodyFormat = "unable to unmarshal request body "
	ErrEmptyMultipartData = "empty multipart form data "
)
View Source
const (
	ERR_CODE_UnexpectedBody = 999
)

Variables

This section is empty.

Functions

This section is empty.

Types

type CallerFunc

type CallerFunc[ReqT any, RespT any] func(ctx context.Context, req ReqT) (RespT, tiny_errors.ErrorHandler)

A function that is called to process request.

ReqT - type of request body RespT - type of response body

type HandlerMaker

type HandlerMaker[ReqT any, RespT any] struct {
	// contains filtered or unexported fields
}

func New

func New[ReqT any, RespT any](w http.ResponseWriter, r *http.Request, logger logger.Logger, caller CallerFunc[ReqT, RespT]) *HandlerMaker[ReqT, RespT]

Create new handler instance

**caller** should be a function that implements type CallerFunc[ReqT, RespT]

func (*HandlerMaker[ReqT, RespT]) Run

func (h *HandlerMaker[ReqT, RespT]) Run(successStatus int)

Run handler and send response with status code

func (*HandlerMaker[ReqT, RespT]) WithJSON added in v1.1.0

func (h *HandlerMaker[ReqT, RespT]) WithJSON() *HandlerMaker[ReqT, RespT]

Parsing JSON-body of request.

Request type should include fields with tags of json

Example:

type YourRequest struct {
		FieldName string `json:"field_name"`
}

func (*HandlerMaker[ReqT, RespT]) WithMultipart

func (h *HandlerMaker[ReqT, RespT]) WithMultipart(maxMemory int64) *HandlerMaker[ReqT, RespT]

Parsing multipart-data from request body.

Request type should include fields with tags of mapstructure.

If field is an array of files you should set tag name as files[] and type []*multipart.FileHeader(mime/multipart.FileHeader)

If field is file and not array of files you should set tag with field name without brackets and type *multipart.FileHeader(mime/multipart.FileHeader)

Other fields should have string type(mime/multipart.Form)

File types

  • []*multipart.FileHeader - field with array of files. Should contain square brackets in name
  • *multipart.FileHeader - field with single file. Should not contain square brackets in field name

Example

type YourRequest struct {
	MultipleFiles []*multipart.FileHeader `mapstructure:"multiple_files[]"`
	SingleFile *multipart.FileHeader 	`mapstructure:"single_file"`
	Name string `mapstructure:"name"`
}

Supported nested structures.

Example:

type Recipient struct {
	Name string `json:"name,omitempty" mapstructure:"name"`
	Age  string `json:"age,omitempty" mapstructure:"age"`
}

type CreateOrder struct {
	Recipient  Recipient               `json:"recipient" mapstructure:"recipient"`
	Content    map[string]string       `json:"content" mapstructure:"content"`
}

Request body(multipart-form):

{
	"recipient[name]": "John",
	"recipient[age]": "30",
	"content[title]": "content title",
	"content[body]": "content body"
}

Result:

func main() {
	// ...
	var order CreateOrder
	fmt.Println(order.Recipient.Name) // John
	fmt.Println(order.Recipient.Age) // 30
	fmt.Println(order.Content["title"]) // content title
	fmt.Println(order.Content["body"]) // content body
}

func (*HandlerMaker[ReqT, RespT]) WithQuery

func (h *HandlerMaker[ReqT, RespT]) WithQuery() *HandlerMaker[ReqT, RespT]

Parsing URL-query params from request.

Request type should include fields with tags of mapstructure.

Example:

type YourRequest struct {
		FieldName string `mapstructure:"field_name"`
}

func (*HandlerMaker[ReqT, RespT]) WithVars

func (h *HandlerMaker[ReqT, RespT]) WithVars() *HandlerMaker[ReqT, RespT]

Parsing URI vars using gorilla/mux

Request type should include fields with tags of mapstructure.

Example:

type YourRequest struct {
		FieldName string `mapstructure:"field_name"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL