It’s possible to add functionalities to your APIs just by using plugins. ApiHub supports two type: Middleware and Transformer.

Middleware

Middleware is a wrapper around your API that decorates the requests without adding logic in the application. It’s supposed to run before dispatching the request to the API. It’s allowed to use as many middlewares as you want, since they implement the interface below:

609
type Middleware interface {
  Configure(cfg string)
  Serve(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

Writting a Middleware

package middleware

import (
  "encoding/json"
  "net/http"

  "github.com/rs/cors"
)

type Cors struct {
  AllowedOrigins   []string `json:"allowed_origins"`
  AllowedMethods   []string `json:"allowed_methods"`
  AllowedHeaders   []string `json:"allowed_headers"`
  ExposedHeaders   []string `json:"exposed_headers"`
  AllowCredentials bool     `json:"allow_credentials"`
  MaxAge           int      `json:"max_age"`
  Debug            bool     `json:"debug"`
}

func NewCorsMiddleware() Middleware {
  return &Cors{}
}

func (c *Cors) Serve(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  cors := cors.New(cors.Options{
    AllowedOrigins:   c.AllowedOrigins,
    AllowedMethods:   c.AllowedMethods,
    AllowedHeaders:   c.AllowedHeaders,
    ExposedHeaders:   c.ExposedHeaders,
    AllowCredentials: c.AllowCredentials,
    MaxAge:           c.MaxAge,
    Debug:            c.Debug,
  })
  cors.ServeHTTP(rw, r, next)
}

func (c *Cors) Configure(cfg string) {
  json.Unmarshal([]byte(cfg), c)
}

After that, it’s needed to add the middleware to the Gateway:

gw.Middleware().Add("cors", NewCorsMiddleware)

The response:

HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-methods: PUT
access-control-allow-origin: http://helloworld.apihub.dev
access-control-max-age: 10
vary: Origin
date: Sat, 16 May 2015 13:40:44 GMT
content-length: 0
content-type: text/plain; charset=utf-8
Connection: keep-alive

Using a Middleware

To use a Middleware, it’s needed to create a config for each service and it’s needed to use the name you used when adding it to the Gateway:

curl -XOPTIONS -H 'Access-Control-Request-Method: PUT' -H 'Origin: http://helloworld.apihub.dev' http://helloworld.apihub.dev/ -i
services := []*account.Service{&account.Service{Endpoint: "http://www.example.org", Subdomain: "example"}}
confCors := &account.Plugin{
  Name:    "cors",
  Service: services[0].Subdomain,
  Config:  map[string]interface{}{"allowed_origins": []string{"http://helloworld.apihub.dev"}, "debug": true, "allowed_methods": []string{"DELETE", "PUT"}, "allow_credentials": true, "max_age": 10},
}
confCors.Save()

Transformer

Transformer is supposed to run after the API response, just before writing the final response.

613
type Filter func(*http.Request, *http.Response, *bytes.Buffer)

Writting a Transform

func FooTransformer(r *http.Request, w *http.Response, body *bytes.Buffer) {
  w.Header.Set("Content-Type", "text/plain")
  body.Reset()
  body.Write([]byte("Foo"))
}

After that, it’s needed to add the transformer to the Gateway:

gateway.Transformer().Add("FooTransformer", FooTransformer)

Using a Transform

To use a Transformer, you just need to use the name you used when adding it to the Gateway:

services := []*account.Service{&account.Service{Endpoint: "http://www.example.org", Subdomain: "example",Transformers: []string{"FooTransformer"}}}