Skip to content

GO KIT vs Mux vs net/http

GoKit

GoKit is more of do it urself thing where they define the flow and leave it to us to define the functions

https://github.com/go-kit/kit/blob/master/transport/http/client.go#L90

https://github.com/go-kit/kit/blob/master/transport/http/server.go#L95

Comparison

Server Side & Client Side

Sever Side

In server side for each endpoint we can write

  1. ServerBeforefns
    1. typically used for getting request headers, token data etc and putting into context
  2. Decode fn
    1. request json to struct conversion
  3. Enpoint fn
    1. calls the service implementation
  4. ServerAfter fn
    1. for any cleanup work
  5. Encode fn
    1. response struct to json

Error Handling

Anypoint if there is an error, we can also use an Error handler to handle the error. Basically do something like REST http code to service error code mapping. Its left upto us on how to define this

Client Side

  1. Client gets inputs and makes a struct
  2. Which is encoded into json and sent as payload in req
  3. Similar to server side here also we have ClientBefore and ClientAfter fns

Plugging Middlewares

Since this only recommends a certain format of fns, and all of these fns actually take in a request and give a response.. they say we can plugin any sort of transport (http, grpc etc)... Havent explored to this level but the go-kit github has examples

Also it is very easy to chain endpoint fn - mainly used for plugging middlewares like logging

typeloggingMiddlewarestruct {
    next   Service
    logger log.Logger
}

func NewLoggingMiddleware(logger log.Logger) Middleware {
    returnfunc(next Service) Service {
        return &loggingMiddleware{
            next:   next,
            logger: logger,
        }
    }
}

func (mw loggingMiddleware) PostPackage(ctx context.Context, packageOptions *PackageRequestMeta, valuesFile *fileUtils.InputFile, archiveFile *fileUtils.InputFile) (application *v1alpha1.Application, err error) {
    deferfunc(begin time.Time) {
        mw.logger.Log("method", "PostPackage", "took", time.Since(begin), "err", err)
    }(time.Now())
    return mw.next.PostPackage(ctx, packageOptions, valuesFile, archiveFile)
}

// the NewLoggingMiddleware fn is like a higher order fn
// I can pass any service to it ..

deployService = deploy.New(conf, logger)
deployService = deploy.NewLoggingMiddleware(logger)(deployService)

It takes a while to get used to this but its very powerful.. I often get confused with all the abstractions and have to lookup stuff.

In postPackage fn, it registers a deferred fn with parameter time.Now for begin then it calls the actual service implementation PostPackage. Once its executed and control returns here, it will log the execution time

Constraints

Its hard to understand go/kit unless you run both client and server in debug mode in vscode and trace the steps

References

Appendix

There are also ServerFinalizer and ClientFinalizer functions but I havent used them much


Last update: November 7, 2023
Back to top