Endpoint Plugin

Bring your own custom endpoint to pREST

With prestd's http plugin system it is possible to create new endpoints in the "private" URI,

The plugin endpoint has the following default: /_PLUGIN/{file}/{func}

Naming patterns

The plugin endpoint (/_PLUGIN/{file}/{func}) receives two parameters:

  • File name: The name of the file without the extension ({file})

  • Function name: The name of the function ({func})

File name

The file name will be used on the endpoint to identify which library will be loaded when it receives the first access.

After the first access the library will not be loaded again, it will only be executed, i.e., if the file (.so) is changed after the first execution it will have no effect because it has already been loaded.

Function name

When talking about a compiled library we have no way of identifying its functions. Given this characteristic we have defined some name and behavior patterns to develop libraries for prestd.

function name: {HTTP Method}{Function Name}Handler

  • {HTTP Method}: The HTTP method that the function will be called for (in upper case letters)

  • {Function Name}: The name of the function that will be called

  • Handler: The suffix of the function name - it is always Handler

fmt.Sprintf("%s%sHandler", r.Method, funcName)

Example

  • Source code name: ./lib/src/hello.go

  • Library file name: ./lib/hello.so

  • Function name: GETHelloHandler

  • Endpoint: /_PLUGIN/hello/Hello

  • Verb HTTP: GET

// all plugins must have their package name as `main`
// each plugin is isolated at compile time
package main

import (
 "encoding/json"
)

var (
 // HTTPVars route variables for the current request
 HTTPVars map[string]string
 // URLQuery parses RawQuery and returns the corresponding values
 URLQuery map[string][]string
)

// Response return structure of the get method
type Response struct {
 HTTPVars map[string]string   `json:"http_vars"`
 URLQuery map[string][]string `json:"url_query"`
 MSG      string              `json:"msg"`
}

// GETHelloHandler plugin
// function is invoked via [go language plugin](https://pkg.go.dev/plugin),
// it is not possible to pass parameters, that's why there are global
// variables to receive data from http protocol
//
// BUILD:
// go build -o lib/hello.so -buildmode=plugin lib/src/hello.go
func GETHelloHandler() (ret string) {
 resp := Response{
  HTTPVars: HTTPVars,
  URLQuery: URLQuery,
  MSG:      "Hello plugin caller!",
 }
 respJSON, err := json.Marshal(resp)
 if err != nil {
  return
 }
 ret = string(respJSON)
 return
}

// GETHelloHandler plugin
// same function as GETHelloHandler, but this time we can return status code.
func GETHelloWithStatusHandler() (ret string, code int) {
	resp := Response{
		HTTPVars: HTTPVars,
		URLQuery: URLQuery,
		MSG:      "Hello plugin caller!",
	}
	respJSON, err := json.Marshal(resp)
	if err != nil {
		return
	}
	ret = string(respJSON)
	code = http.StatusAccepted
	return
}

Request:

GET /_PLUGIN/hello/Hello?abc=123 HTTP/1.1

Response:

{
  "http_vars": {
    "file": "hello",
    "func": "Hello"
  },
  "url_query": {
    "abc": [
      "123"
    ]
  },
  "msg": "Hello plugin caller!"
}