natsmicromw

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2024 License: MIT Imports: 4 Imported by: 1

README

NATS micro Middleware

NATS micro Middleware is a Go package that provides middleware functionality for building middleware-enabled microservices using NATS.go. It is built on top of the NATS micro package

Overview

The natsmicromw provides a thin wrapper around micro.Service and micro.Group as well as implements the same interfaces.

Basic usage

To start using the natsmicromw package, import it in your application:

import "github.com/Karimerto/natsmicromw"

Usage is almost identical to the micro package itself. The only difference is the middleware(s) as well as support for context-included Request.

func DurationMiddleware(next micro.Handler) micro.Handler {
    return micro.HandlerFunc(func(req micro.Request) {
        // Record start time
        start := time.Now()

        // Call the next middleware or handler function
        // Note that it must call the `Handle` function specifically
        next.Handle(req)

        // Record elapsed time and payload size
        elapsed := time.Since(start)
        log.Printf("Duration: %s", elapsed)
    })
}

nc, _ := nats.Connect(nats.DefaultURL)

// request handler
echoHandler := func(req micro.Request) {
    req.Respond(req.Data())
}

srv, err := natsmicromw.AddService(nc, micro.Config{
    Name:        "EchoService",
    Version:     "1.0.0",
    // base handler
    Endpoint: &micro.EndpointConfig{
        Subject: "svc.echo",
        Handler: micro.HandlerFunc(echoHandler),
    },
}, DurationMiddleware)

After creating the service, it can be accessed by publishing a request on endpoint subject. For given configuration, run:

nats req svc.echo "hello!"

To get:

17:37:32 Sending request on "svc.echo"
17:37:32 Received with rtt 365.875µs
hello!

As well as:

17:37:32 Duration: 28.634µs

Context-based usage

Context-based middleware adds a custom Request that includes a context.Context that can be carried through the entire middleware chain.

type startContextKey struct{}

func DurationContextMiddleware(next natsmicromw.ContextHandlerFunc) natsmicromw.ContextHandlerFunc {
    // Note that this is a regular function that is returned
    return func(req *natsmicromw.Request) error {
        // Record start time
        start := time.Now()

        // Call the next middleware or handler function
        ctx := context.WithValue(req.Context(), requestIdContextKey{}, start)
        err := next(req.WithContext(ctx))

        // Record elapsed time and payload size
        elapsed := time.Since(start)
        log.Printf("Duration: %s", elapsed)

        return err
    }
}

func StartFromContext(ctx context.Context) time.Time {
    start, ok := ctx.Value(startContextKey{}).(time.Time)
    if !ok {
        return time.Now()
    }
    return start
}

nc, _ := nats.Connect(nats.DefaultURL)

// request handler
echoHandler := func(req micro.Request) {
    req.Respond(req.Data())
}

srv, err := micro.AddService(nc, micro.Config{
    Name:        "EchoService",
    Version:     "1.0.0",
    // Note that base handler does not work with context-based middleware
}, DurationContextMiddleware)

srv.AddContextEndpoint("echo", func(req *natsmicromw.Request) error {
    started := StartFromContext(req.Context())
    log.Println("Request was started at:", started)
    req.Respond(req.Data())
    return nil
})

New MicroRequest and MicroReply usage

A third type of middleware adds support for a custom MicroRequest and MicroReply. The point of these structs is to enable the user to modify both the headers and data of any incoming request and outgoing reply. This also includes a new type of handler function that takes MicroRequest as a parameter and must return MicroReply and an error.

func ContentChangeMiddleware(next natsmicromw.MicroHandlerFunc) natsmicromw.MicroHandlerFunc {
    return func(req *natsmicromw.MicroRequest) (*natsmicromw.MicroReply, error) {
        // Call the next function in the middleware chain (or the actual handler)
        res, err := next(req)
        if err != nil {
            return res, err
        }

        // Prepend some data to the response
        res.Data = append([]byte("Hello from Middleware: "), res.Data...)
        return res, err
    }
}

nc, _ := nats.Connect(nats.DefaultURL)

// request handler
echoHandler := func(req *natsmicromw.MicroRequest) (*natsmicromw.MicroReply, error) {
    return natsmicromw.NewMicroReply(req.Data), nil
}

svc, err := natsmicromw.AddMicroService(nc, micro.Config{
    Name:        "EchoService",
    Version:     "1.0.0",
}, ContentChangeMiddleware)

g.AddMicroEndpoint("echo", echoHandler)

Contributing

Contributions are welcome! If you find a bug or have a feature request, please open an issue. If you would like to contribute code, please fork the repository and create a pull request.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Version

func Version() string

Version is the current release version.

Types

type ContextHandlerFunc

type ContextHandlerFunc func(*Request) error

type ContextMiddlewareFunc

type ContextMiddlewareFunc func(ContextHandlerFunc) ContextHandlerFunc

Middleware function that takes a `ContextHandlerFunc` and returns a new `ContextHandlerFunc`

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group represents a Microservice group with middleware support.

func (*Group) AddContextEndpoint

func (g *Group) AddContextEndpoint(name string, handler ContextHandlerFunc, opts ...micro.EndpointOpt) error

AddContextEndpoint registers an endpoint with the given name on a specific subject within a group.

func (*Group) AddEndpoint

func (g *Group) AddEndpoint(name string, handler micro.Handler, opts ...micro.EndpointOpt) error

AddEndpoint registers new endpoints on a service. The endpoint's subject will be prefixed with the group prefix.

func (*Group) AddGroup

func (g *Group) AddGroup(name string, opts ...micro.GroupOpt) *Group

AddGroup creates a new group, prefixed by this group's prefix.

func (*Group) AddMicroEndpoint added in v0.1.0

func (g *Group) AddMicroEndpoint(name string, handler MicroHandlerFunc, opts ...micro.EndpointOpt) error

AddMicroEndpoint registers an endpoint with the given name on a specific subject within a group.

func (*Group) Use

func (g *Group) Use(fns ...MiddlewareFunc) *Group

Use is an alias for WithMiddleware, adding middleware functions to the Microservice group.

func (*Group) UseContext

func (g *Group) UseContext(fns ...ContextMiddlewareFunc) *Group

UseContext is an alias for WithContextMiddleware, adding context middleware functions to the Microservice group.

func (*Group) UseMicro added in v0.1.0

func (g *Group) UseMicro(fns ...MicroMiddlewareFunc) *Group

UseMicro is an alias for WithMicroMiddleware, adding Micro middleware functions to the Microservice group.

func (*Group) WithContextMiddleware

func (g *Group) WithContextMiddleware(fns ...ContextMiddlewareFunc) *Group

WithContextMiddleware adds context middleware functions to the Microservice group.

func (*Group) WithMicroMiddleware added in v0.1.0

func (g *Group) WithMicroMiddleware(fns ...MicroMiddlewareFunc) *Group

WithMicroMiddleware adds Micro middleware functions to the Microservice group.

func (*Group) WithMiddleware

func (g *Group) WithMiddleware(fns ...MiddlewareFunc) *Group

WithMiddleware adds middleware functions to the Microservice group.

type HandlerError

type HandlerError struct {
	Description string `json:"description"`
	Code        string `json:"code"`
}

func (*HandlerError) Error

func (e *HandlerError) Error() string

type MicroHandlerFunc added in v0.1.0

type MicroHandlerFunc func(*MicroRequest) (*MicroReply, error)

type MicroMiddlewareFunc added in v0.1.0

type MicroMiddlewareFunc func(MicroHandlerFunc) MicroHandlerFunc

type MicroReply added in v0.1.0

type MicroReply struct {
	Headers micro.Headers
	Data    []byte
}

func NewMicroReply added in v0.1.0

func NewMicroReply(data []byte) *MicroReply

Create a new MicroReply

func NewMicroReplyFromRequest added in v0.1.0

func NewMicroReplyFromRequest(data []byte, req *MicroRequest) *MicroReply

Create a new MicroReply and copy headers from the original request

func (*MicroReply) HeaderAdd added in v0.1.0

func (r *MicroReply) HeaderAdd(key, value string)

func (*MicroReply) HeaderDel added in v0.1.0

func (r *MicroReply) HeaderDel(key string)

func (*MicroReply) HeaderGet added in v0.1.0

func (r *MicroReply) HeaderGet(key string) string

func (*MicroReply) HeaderSet added in v0.1.0

func (r *MicroReply) HeaderSet(key, value string)

func (*MicroReply) HeaderValues added in v0.1.0

func (r *MicroReply) HeaderValues(key string) []string

type MicroRequest added in v0.1.0

type MicroRequest struct {
	Subject string
	Reply   string
	Headers micro.Headers
	Data    []byte
	// contains filtered or unexported fields
}

func (*MicroRequest) Context added in v0.1.0

func (r *MicroRequest) Context() context.Context

Context returns the current attached message context.

func (*MicroRequest) HeaderAdd added in v0.1.0

func (r *MicroRequest) HeaderAdd(key, value string)

func (*MicroRequest) HeaderDel added in v0.1.0

func (r *MicroRequest) HeaderDel(key string)

func (*MicroRequest) HeaderGet added in v0.1.0

func (r *MicroRequest) HeaderGet(key string) string

func (*MicroRequest) HeaderSet added in v0.1.0

func (r *MicroRequest) HeaderSet(key, value string)

func (*MicroRequest) HeaderValues added in v0.1.0

func (r *MicroRequest) HeaderValues(key string) []string

func (*MicroRequest) WithContext added in v0.1.0

func (r *MicroRequest) WithContext(ctx context.Context) *MicroRequest

WithContext sets a new message context and returns a new MicroRequest.

type MiddlewareFunc

type MiddlewareFunc func(micro.Handler) micro.Handler

MiddlewareFunc defines the type for middleware functions.

type Request

type Request struct {
	micro.Request
	// contains filtered or unexported fields
}

Request extends the micro.Request type to include a custom context.

func (*Request) Context

func (r *Request) Context() context.Context

Context returns the current attached message context.

func (*Request) RespondWithOriginalHeaders added in v0.0.2

func (r *Request) RespondWithOriginalHeaders(response []byte, opts ...micro.RespondOpt) error

func (*Request) WithContext

func (r *Request) WithContext(ctx context.Context) *Request

WithContext sets a new message context and returns a new Request.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service represents a Microservice with middleware support.

func AddContextService

func AddContextService(nc *nats.Conn, config micro.Config, fns ...ContextMiddlewareFunc) (*Service, error)

AddContextService creates a new Microservice with middleware support. Note that this version does not support defining an endpoint in the initial config. If any is defined, it will not use any of the context-based middlewares.

func AddMicroService added in v0.1.0

func AddMicroService(nc *nats.Conn, config micro.Config, fns ...MicroMiddlewareFunc) (*Service, error)

AddMicroService creates a new Microservice with middleware support. Note that this version does not support defining an endpoint in the initial config. If any is defined, it will not use any of the context-based middlewares.

func AddService

func AddService(nc *nats.Conn, config micro.Config, fns ...MiddlewareFunc) (*Service, error)

AddService creates a new Microservice with middleware support.

func (*Service) AddContextEndpoint

func (s *Service) AddContextEndpoint(name string, handler ContextHandlerFunc, opts ...micro.EndpointOpt) error

AddContextEndpoint registers an endpoint with the given name on a specific subject.

func (*Service) AddEndpoint

func (s *Service) AddEndpoint(name string, handler micro.Handler, opts ...micro.EndpointOpt) error

AddEndpoint registers an endpoint with the given name on a specific subject.

func (*Service) AddGroup

func (s *Service) AddGroup(name string, opts ...micro.GroupOpt) *Group

AddGroup returns a Group interface, allowing for more complex endpoint topologies. A group can be used to register endpoints with a given prefix.

func (*Service) AddMicroEndpoint added in v0.1.0

func (s *Service) AddMicroEndpoint(name string, handler MicroHandlerFunc, opts ...micro.EndpointOpt) error

AddMicroEndpoint registers an endpoint with the given name on a specific subject.

func (*Service) Info

func (s *Service) Info() micro.Info

Info returns the service info.

func (*Service) Reset

func (s *Service) Reset()

Reset resets all statistics (for all endpoints) on a service instance.

func (*Service) SetDefaultContext

func (s *Service) SetDefaultContext(ctx context.Context)

SetDefaultContext sets the default context to be used by the service. This context will be used if no custom context is provided during endpoint registration.

func (*Service) Stats

func (s *Service) Stats() micro.Stats

Stats returns statistics for the service endpoint and all monitoring endpoints.

func (*Service) Stop

func (s *Service) Stop() error

Stop drains the endpoint subscriptions and marks the service as stopped.

func (*Service) Stopped

func (s *Service) Stopped() bool

Stopped informs whether [Stop] was executed on the service.

func (*Service) Use

func (s *Service) Use(fns ...MiddlewareFunc) *Service

Use is an alias for WithMiddleware, adding middleware functions to the Microservice.

func (*Service) UseContext

func (s *Service) UseContext(fns ...ContextMiddlewareFunc) *Service

UseContext is an alias for WithContextMiddleware, adding middleware functions to the Microservice.

func (*Service) UseMicro added in v0.1.0

func (s *Service) UseMicro(fns ...MicroMiddlewareFunc) *Service

UseMicro is an alias for WithMicroMiddleware, adding middleware functions to the Microservice.

func (*Service) WithContextMiddleware

func (s *Service) WithContextMiddleware(fns ...ContextMiddlewareFunc) *Service

WithContextMiddleware adds middleware functions to the Microservice.

func (*Service) WithMicroMiddleware added in v0.1.0

func (s *Service) WithMicroMiddleware(fns ...MicroMiddlewareFunc) *Service

WithMicroMiddleware adds middleware functions to the Microservice.

func (*Service) WithMiddleware

func (s *Service) WithMiddleware(fns ...MiddlewareFunc) *Service

WithMiddleware adds middleware functions to the Microservice.

Directories

Path Synopsis
examples
middleware module

Jump to

Keyboard shortcuts

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