# Server interceptor

### Interface implementation

* To add an interceptor, you need to implement the following functionality
* Then via`client.AddInterceptor`register the interceptor; afterwards when the service starts it will call the corresponding interceptor through configuration

```go

// UnaryServerInfo contains metadata about a single (unary) RPC call.
// This is passed to interceptors to provide context about the server and method being called.
type UnaryServerInfo struct {
	// Server is the underlying service implementation.
	Server any
	// FullMethod is the path to the RPC (e.g., "/user.UserService/GetUser").
	FullMethod string
	// Protocol identifies the transport (e.g., "grpc", "rest").
	Protocol string
}

// UnaryHandler is the signature of the final business logic or the next step in the chain.
type UnaryHandler func(ctx context.Context, req any) (any, error)

// UnaryServerInterceptor is a middleware function that wraps the request execution.
// It can modify the context/request before execution or the response/error after.
type UnaryServerInterceptor func(ctx context.Context, req any, info *UnaryServerInfo, handler UnaryHandler) (resp any, err error)

// ServerInterceptor is the interface for pluggable middleware components.
type ServerInterceptor interface {
	// Name returns the unique identifier for the interceptor (e.g., "logger").
	Name() string
	// Interceptor returns the actual function that performs the wrapping.
	Interceptor() UnaryServerInterceptor
}

```

### Supported implementations

* [accessLog](https://asjard.gitbook.io/docs/en/components/interceptors/interceptor-server/interceptor-server-accesslog)
* [i18n](https://asjard.gitbook.io/docs/en/components/interceptors/interceptor-server/interceptor-server-i18n)
* [Monitoring](https://asjard.gitbook.io/docs/en/components/interceptors/interceptor-server/interceptor-server-metrics)
* [panic log](https://github.com/asjard/asjard/blob/develop/docs/en/user-guide/inteceptor-server-panic.md)
* [rate limiting](https://github.com/asjard/asjard/blob/develop/docs/en/user-guide/inteceptor-server-ratelimit.md)
* [request parameter parsing](https://github.com/asjard/asjard/blob/develop/docs/en/user-guide/inteceptor-server-restReadEntity.md)
* [distributed tracing](https://github.com/asjard/asjard/blob/develop/docs/en/user-guide/inteceptor-server-trace.md)
* [parameter validation](https://github.com/asjard/asjard/blob/develop/docs/en/user-guide/inteceptor-server-validate.md)

### Configuration

```yaml
asjard:
  ## client configurations
  servers:
    ## Global protocol-agnostic common interceptors
    # interceptors: ""
    ## Global built-in default interceptors
    # builtInInterceptors: panic,rest2RpcContext,validate,errLog,slowLog,cycleChainInterceptor
    ## Protocol-specific configuration
    grpc:
      ## grpc interceptors
      # interceptors: ""
```

Update default interceptors:

```yaml
asjard:
  ## client configurations
  servers:
    ## Global protocol-agnostic common interceptors
    # interceptors: ""
    ## Global built-in default interceptors
    ## Local update syntax
    ## -errLog remove the errLog interceptor
    ## +errLog:customeLog add customeLog interceptor before errLog
    ## errLog+:customeLog add customeLog interceptor after errLog
    ## =errLog:customeLog replace errLog interceptor with customeLog
    ## customeLog append customeLog interceptor to the end of the default interceptors
    # builtInInterceptors: -errLog,customeLog
```

### Custom implementation

```go
package interceptors

import (
	"context"
	"runtime/debug"

	"github.com/asjard/asjard/core/logger"
	"github.com/asjard/asjard/core/server"
	"github.com/asjard/asjard/core/status"
)

const (
	// PanicInterceptorName is the unique identifier for this interceptor.
	PanicInterceptorName = "panic"
)

func init() {
	// Register the panic recovery interceptor globally for all server protocols.
	server.AddInterceptor(PanicInterceptorName, NewPanic)
}

// Panic represents the recovery interceptor component.
type Panic struct{}

// NewPanic initializes the panic interceptor.
func NewPanic() (server.ServerInterceptor, error) {
	return &Panic{}, nil
}

// Interceptor returns the middleware function that handles panic recovery.
func (*Panic) Interceptor() server.UnaryServerInterceptor {
	return func(ctx context.Context, req any, info *server.UnaryServerInfo, handler server.UnaryHandler) (resp any, err error) {
		// Use defer to ensure the recovery logic runs even if the handler panics.
		defer func() {
			if rcv := recover(); rcv != nil {
				// 1. Collect diagnostic information about the crash.
				args := []any{
					"err", rcv, // The actual panic object/message.
					"req", req, // The request payload that triggered the panic.
					"method", info.FullMethod, // The endpoint being called.
					"protocol", info.Protocol, // gRPC or REST.
					"stack", string(debug.Stack()), // The full goroutine stack trace.
				}

				// 2. Log the incident with Error level for alerting and debugging.
				logger.L(ctx).Error("request panic", args...)

				// 3. Mask the internal crash from the client by returning a
				// standardized 500 Internal Server Error.
				err = status.InternalServerError()
			}
		}()

		// Execute the next interceptor or the final business logic handler.
		return handler(ctx, req)
	}
}

// Name returns the interceptor's unique name.
func (*Panic) Name() string {
	return PanicInterceptorName
}

```
