REST Handler#


Tutorial code: REST Handler

In this tutorial, you will learn how to add a REST API to a plugin. Before running through this tutorial, you should complete the Hello World tutorial and the Plugin Dependencies tutorial.

You should also be familiar with REST APIs. To learn about REST APIs, or if you need a quick refresher, check out the REST API Tutorial.

Note

MyPlugin is the name of the plugin used in this tutorial. Note that any concepts, explanations, tasks and code block contents used in this tutorial can be applied to the HelloWorld plugin used in the previous tutorials.


Each plugin that requires a REST API needs to register its own custom handler with the REST plugin. You perform this task by using the registration API:

type HandlerProvider func(formatter *render.Render) http.HandlerFunc

type HTTPHandlers interface {
    RegisterHTTPHandler(path string, provider HandlerProvider, methods ...string) *mux.Route
    // ...
}

To use the REST plugin, first define it as a dependency in your plugin:

type MyPlugin struct {
    infra.PluginDeps
    REST rest.HTTPHandlers
}

Note that the dependency is defined as an interface. This means that it can be satisfied by any object that implements the interface methods.

The rest.HTTPHandlers interface is defined in plugin_api_rest.go file.


Next, wire the dependency into the plugin’s constructor. The code block below uses the default REST plugin of rest.DefaultPlugin. Most Ligato infrastructure plugins have a default plugin instance defined as a global variable.

func NewMyPlugin() *MyPlugin {
    // ...
    p.REST = &rest.DefaultPlugin
    return p
}

Now, you can define your handler:

func (p *MyPlugin) fooHandler(formatter *render.Render) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            p.Log.Errorf("Error reading body: %v", err)
            http.Error(w, "can't read body", http.StatusBadRequest)
            return
        }
        formatter.Text(w, http.StatusOK, fmt.Sprintf("Hello %s", body))
    }
}

Finally, register your handler with the REST plugin using your plugin’s Init() method:

func (p *MyPlugin) Init() error {
    // ...
    p.REST.RegisterHTTPHandler("/greeting", p.fooHandler, "POST")
    return nil
}

Run the REST Handler tutorial code

  1. Open a terminal session.

  2. Change to the 03_rest-handler folder:
cn-infra git:(master) cd examples/tutorials/03_rest-handler
  1. Run code:
go run main.go

Example output:

INFO[0000] Starting agent version: v0.0.0-dev            BuildDate= CommitHash= loc="agent/agent.go(134)" logger=agent
INFO[0000] Listening on http://0.0.0.0:9191              loc="rest/plugin_impl_rest.go(109)" logger=http
INFO[0000] Agent started with 2 plugins (took 1ms)       loc="agent/agent.go(179)" logger=agent

Note

You might see a deny/allow incoming connection warning message. Either one is okay for this example.

  1. Open a new terminal session and type in this curl command:
curl -X POST -d 'John' -H "Content-Type: application/json" http://localhost:9191/greeting

Example output:

Hello John

Example output after interrupt:

^CINFO[0045] Signal interrupt received, stopping.          loc="agent/agent.go(196)" logger=agent
INFO[0045] Stopping agent                                loc="agent/agent.go(269)" logger=agent
INFO[0045] Agent stopped                                 loc="agent/agent.go(291)" logger=agent