Backend Development 11 min read

TarsGo Interceptors (Filters and Middleware) Tutorial for Go Developers

This tutorial explains how to use and implement server‑side and client‑side interceptors (filters and middleware) in TarsGo, covering their definitions, registration methods, code examples, and execution priority to help Go developers efficiently add logging, authentication, rate‑limiting, tracing and other cross‑cutting concerns.

TAL Education Technology
TAL Education Technology
TAL Education Technology
TarsGo Interceptors (Filters and Middleware) Tutorial for Go Developers

This article is the third part of the “Tars tutorial for Go developers”, focusing on interceptors (filters and middleware) in TarsGo.

Server‑side Interceptor (Filter)

The interceptor definition is:

// Dispatch server side Dispatch
type Dispatch func(context.Context, interface{}, *requestf.RequestPacket, *requestf.ResponsePacket, bool) error

// ServerFilter is used for adding filter for server dispatcher, for implementing plugins like opentracing.
type ServerFilter func(ctx context.Context, d Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error)

Registering a server interceptor can be done with the following functions (only one can be registered with RegisterServerFilter, multiple with RegisterPreServerFilter and RegisterPostServerFilter):

func RegisterServerFilter(f ServerFilter) // register a single server filter
func RegisterPreServerFilter(f ServerFilter) // register a pre‑processing filter, multiple allowed
func RegisterPostServerFilter(f ServerFilter) // register a post‑processing filter, multiple allowed
These three registration methods are deprecated after version 1.5; middleware should be used instead.

Example using the deprecated registration methods:

tars.RegisterServerFilter(func(ctx context.Context, d tars.Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error) {
    // TODO: add pre‑processing logic (e.g., logging, auth, rate‑limit, tracing)
    s := time.Now()
    err = d(ctx, f, req, resp, withContext)
    // TODO: add post‑processing logic
    log.Printf("ServantName: %s, FuncName: %s, req: %v, resp: %v, latency: %s\n", req.SServantName, req.SFuncName, req, resp, time.Now().Sub(s))
    return err
})

tars.RegisterPreServerFilter(func(ctx context.Context, d tars.Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error) {
    // TODO: pre‑processing logic
    return err // returning err will let the server continue processing and only log the error
})

tars.RegisterPostServerFilter(func(ctx context.Context, d tars.Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error) {
    // TODO: post‑processing logic
    return err // returning err will let the server continue processing and only log the error
})

Middleware (Filter)

Middleware is defined as a function that wraps a ServerFilter:

// ServerFilterMiddleware is used for adding multiple filter middlewares for dispatcher, e.g., breaker, rate limit, trace.
type ServerFilterMiddleware func(next ServerFilter) ServerFilter

Register middleware with:

func UseServerFilterMiddleware(sfm ...ServerFilterMiddleware) // can register multiple middlewares

Example:

tars.UseServerFilterMiddleware(func(next tars.ServerFilter) tars.ServerFilter {
    return func(ctx context.Context, d tars.Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error) {
        // TODO: pre‑processing logic (logging, auth, rate‑limit, tracing, etc.)
        s := time.Now()
        err = next(ctx, d, f, req, resp, withContext)
        // TODO: post‑processing logic
        log.Printf("ServantName: %s, FuncName: %s, latency: %s\n", req.SServantName, req.SFuncName, time.Now().Sub(s))
        return err
    }
})

The execution priority of registration methods is:

RegisterServerFilter

UseServerFilterMiddleware

RegisterPreServerFilter / RegisterPostServerFilter

Only the first applicable interceptor in this order will run; later ones are ignored.

Client‑side Interceptor (Filter)

Client interceptor definitions:

// Invoke is used for invoking a Tars server service
type Invoke func(ctx context.Context, msg *Message, timeout time.Duration) (err error)

// ClientFilter is used for filtering request & response on the client, e.g., for opentracing plugins.
type ClientFilter func(ctx context.Context, msg *Message, invoke Invoke, timeout time.Duration) (err error)

Registering client interceptors:

func RegisterClientFilter(f ClientFilter) // only one allowed
func RegisterPreClientFilter(f ClientFilter) // multiple pre‑request filters allowed
func RegisterPostClientFilter(f ClientFilter) // multiple post‑request filters allowed
These registration methods are also deprecated after version 1.5; middleware should be used instead.

Example using the deprecated registration methods:

tars.RegisterClientFilter(func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {
    // TODO: pre‑processing logic
    s := time.Now()
    err = invoke(ctx, msg, timeout)
    // TODO: post‑processing logic
    log.Printf("ServantName: %s, FuncName: %s, req: %v, resp: %v, latency: %s\n", msg.Req.SServantName, msg.Req.SFuncName, msg.Req, msg.Resp, time.Now().Sub(s))
    return err
})

tars.RegisterPreClientFilter(func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {
    // TODO: pre‑processing logic
    return err // returning err lets the client continue and only logs the error
})

tars.RegisterPostClientFilter(func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {
    // TODO: post‑processing logic
    return err // returning err lets the client continue and only logs the error
})

Middleware (Filter)

Client middleware definition:

// ClientFilterMiddleware is used for adding multiple filter middlewares for client, e.g., breaker, rate limit, trace.
type ClientFilterMiddleware func(next ClientFilter) ClientFilter

Register client middleware with:

func UseClientFilterMiddleware(cfm ...ClientFilterMiddleware) // can register multiple middlewares

Example:

tars.UseClientFilterMiddleware(func(next tars.ClientFilter) tars.ClientFilter {
    return func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {
        // TODO: pre‑processing logic (logging, auth, rate‑limit, tracing, etc.)
        s := time.Now()
        err = next(ctx, msg, invoke, timeout)
        // TODO: post‑processing logic
        log.Printf("ServantName: %s, FuncName: %s, latency: %s\n", msg.Req.SServantName, msg.Req.SFuncName, time.Now().Sub(s))
        return err
    }
})

The priority order for client registration methods mirrors the server side:

RegisterClientFilter

UseClientFilterMiddleware

RegisterPreClientFilter / RegisterPostClientFilter

Conclusion

After reading this guide, readers should have a deep understanding of how to use and implement TarsGo interceptors (filters and middleware) on both server and client sides, enabling efficient insertion of logging, authentication, rate‑limiting, tracing and other cross‑cutting concerns.

Example Code Repositories

Server and client interceptor examples are available at:

https://github.com/lbbniu/TarsGo-tutorial/blob/interceptors/client/main.go

https://github.com/lbbniu/TarsGo-tutorial/blob/interceptors/main.go

backendmiddlewareGoFiltersInterceptorsTarsGo
TAL Education Technology
Written by

TAL Education Technology

TAL Education is a technology-driven education company committed to the mission of 'making education better through love and technology'. The TAL technology team has always been dedicated to educational technology research and innovation. This is the external platform of the TAL technology team, sharing weekly curated technical articles and recruitment information.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.