mercredi 4 décembre 2019

Incoming requests: context with custom typed fields

I'm writing a more or less simple web application using go that provides a rest api. When a request comes in, I want to store the id of the user, which is part of the api token, temporarily inside the requests context. After reading some articles and the docs I'm still confused how to make sure that the values, that one attaches to the context using context.WithValue(), can be used without type assertion, but a struct of sorts instead.

This is what I've come up with so far:

// RequestContext contains the application-specific information that are carried around in a request.
type RequestContext interface {
    context.Context
    // UserID returns the ID of the user for the current request
    UserID() uuid.UUID
    // SetUserID sets the ID of the currently authenticated user
    SetUserID(id uuid.UUID)
}

type requestContext struct {
    context.Context           // the golang context
    now             time.Time // the time when the request is being processed
    userID          uuid.UUID // an ID identifying the current user
}

func (ctx *requestContext) UserID() uuid.UUID {
    return ctx.userID
}

func (ctx *requestContext) SetUserID(id uuid.UUID) {
    ctx.userID = id
}

func (ctx *requestContext) Now() time.Time {
    return ctx.now
}

// NewRequestContext creates a new RequestContext with the current request information.
func NewRequestContext(now time.Time, r *http.Request) RequestContext {
    return &requestContext{
        Context: r.Context(),
        now:     now,
    }
}

// RequestContextHandler is a middleware that sets up a new RequestContext and attaches it to the current request.
func RequestContextHandler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        now := time.Now()
        next.ServeHTTP(w, r.WithContext(NewRequestContext(now, r)))
    })
}

I would like to know how I can access the SetUserID() and UserID() functions of the request context inside a handler or if there is an alternative, similar approach.

Aucun commentaire:

Enregistrer un commentaire