0

The package valyala/fasthttp implements the following function type:

type RequestHandler func(ctx *RequestCtx)

It is used in buaazp/fasthttprouter like this:

func (r *Router) Handle(method, path string, handle fasthttp.RequestHandler) {
    //...
}

I am trying to wrap these like this (open for suggestions on implementation):

//myapp/router

type Request struct {
    fasthttp.RequestCtx
}

type RequestHandler func(*Request)

func Handle(method string, path string, handler RequestHandler) {
    //I need to access the fasthttp.RequestCtx stuff in here...
}

How can I achieve this? Or, if this is not the way to go at all, how can I achieve my goal as mentioned below for a router package?


BACKGROUND

Goal: My wish is to wrap tooling packages (sessions, database, routing, etc.) in order to make my app agnostic to the implementation of these packages. I wish to do this primarily for the purpose of being able to extend these with domain-specific functionality, and being able to switch one 3rd party lib for another, if I ever would need to do so. It also makes debugging and logging easier.

Method: I create native types and functions, which map to the functionality of the imported packages.

Problem: I am stuck on how to wrap a foreign (i.e. imported) function type properly.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Arnaud H
  • 881
  • 2
  • 10
  • 16

1 Answers1

0

At all your idea looks very good. Some things you could change:

//myapp/router    

// Using a composition is idiomatic go code 
// this should work. It can't get better.
type Request struct {
    fasthttp.RequestCtx
}

// I would make the RequestHandler as a real Handler. In go it would be
// a interface
type RequestHandler interface{
   Request(*Request)
}
// If you have a function, which needs to access parameters from `Request`
// you should take this as an input.
func Handle(method string, path string, req *Request) {
    //Access Request via req.Request ...
}

Because if you pass a function or an interface into your function, which needs also Request as input the caller needs to create that before he calls your Handle function. Why not change that function just for the input you really need?

apxp
  • 5,240
  • 4
  • 23
  • 43
  • I passed in the functions as arguments to mimic the implementation of the packages. In net/http, its `func Route(w http.ResponseWriter, r *http.Request) {}`, in buaazp/fasthttprouter it's `func Route(ctx *fasthttp.RequestCtx) {}`. If I leave out the function types, how should I declare a route under this implementation? – Arnaud H Mar 11 '17 at 13:22
  • Sorry I didn't understand you. So you want to use the fasthttp as server and combine this with fasthttprouter for the routes. Am I right? – apxp Mar 11 '17 at 16:12
  • Yes, however invisible to the rest of the application. I would like to wrap all of the 3rd party imports into _myapp/router_, so that other packages only import _myapp/router_ and nothing else. My problem lies within declaring routes, as they are formatted as _handlerFunctions_ with signature types from the imported packages. This means they are usually formatted as in my previous comment. Ideally, I'd like to be able to declare a route as `router.GET(path string, ctx router.Context){}` or `router.GET(path string, func(ctx router.Context) {})`, and map these to fasthttprouter implementation... – Arnaud H Mar 11 '17 at 16:48
  • 1
    If you want to write some middleware, which wraps the handler, the handle function has to return also a handler. Look here: https://medium.com/@matryer/the-http-handler-wrapper-technique-in-golang-updated-bc7fbcffa702#.hetv7iibf – apxp Mar 11 '17 at 18:30
  • Thank you for that link! I was able to wrap the router package, however it still relies on a `func Route(w http.ResponseWriter, r *http.Request) {}` type of implementation. I guess it's as good as it's gonna get for now. – Arnaud H Mar 13 '17 at 10:04