natsproxy

package module
v0.0.0-...-86e790e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2022 License: MIT Imports: 20 Imported by: 0

README

REST to NATS proxy.

REST API over NATS protocol.

Build Status GoReport GoDoc Coverage Status

The microframework for building the REST API on NATS messaging platform. As the part of the framework is proxy bridging HTTP protocol to NATS protocol.

Example usage
service connected to NATS via nats-proxy client:
	clientConn, _ := nats.Connect(nats.DefaultURL)
	natsClient, _ := NewNatsClient(clientConn)
	natsClient.GET("/test/:event/:session", func(c *Context) {
		reqEvent = c.PathVariable("event")
		reqSession = c.PathVariable("session")

		respStruct := struct {
			User string
		}{
			"Radek",
		}

		c.JSON(200, respStruct)
	})
	defer clientConn.Close()
nats-proxy gateway
	proxyConn, _ := nats.Connect(nats.DefaultURL)
	proxy, _ := NewNatsProxy(proxyConn)
	http.Handle("/", proxy)
	defer proxyConn.Close()
HTTP client
resp, err := http.Get("http://127.0.0.1:3000/test/12324/123")
WebSocket support

The web socket support is in early stage, but it is working. The proxy does not support close notifications for the client side and there is a lot of work to be done.

	clientConn, _ := nats.Connect(nats_url)
	natsClient, _ := NewNatsClient(clientConn)
	
	// Basic nats-proxy handler
	natsClient.GET("/ws/:token", func(c *Context) {
		
		// Test if the client 
		// contains websocket handshake
		if c.Request.IsWebSocket() {
			
			// If so, the DoUpgrade 
			// flag must be set to true, 
			// to notify proxy to do the websocket upgrade
			c.Response.DoUpgrade = true
			
			// Each websocket connection has its
			// unique id, which is practically 
			// the subject of NATS
			socketID, err := c.GetWebsocketID()
			
			// The handler for incoming 
			// messages could be set.
			natsClient.HandleWebsocket(socketID, func(m *nats.Msg) {
				
				// WriteWebsocket writes
				// the message directly to
				// NATS subject
				natsClient.WriteWebsocket(socketID, []byte("Hi there"))
			})
		}
	})
Advanced features
Proxy hook

Proxy hook is feature designed to change the response before it's written to http response. This feature could be used for example to enrich the header by special content or audit outgoing data.

multiProxy.AddHook("/login.*", loginHook)

func loginHook(resp *natsproxy.Response) {
    // Do something 
    // with the response
    // e.g change outgoing header.
	resp.Header.Set(TokenHeader, token.RefToken)
}
Client middleware

The client middleware feature is inspired by gin framework. Context could be processed before it is processed by specific handler. The example below shows how to use middleware to log all incoming requests.

natsClient.Use(logger)

func logger(c *natsproxy.Context) {
	log.Infof("%s:%s from %s", c.Request.Method, c.Request.URL)
}

Documentation

Overview

Package natsproxy is a generated protocol buffer package.

It is generated from these files:

protobuf.proto

It has these top-level messages:

Values
Request
Response

Index

Constants

View Source
const (
	// GET method constant
	GET = "GET"
	// POST method constant
	POST = "POST"
	// PUT method constant
	PUT = "PUT"
	// DELETE method constant
	DELETE = "DELETE"
)

Variables

View Source
var (
	// ErrNatsClientNotConnected is returned
	// if the natsclient inserted
	// in NewNatsProxy is not connected.
	ErrNatsClientNotConnected = fmt.Errorf("Client not connected")
)

Functions

func IsWebSocketRequest

func IsWebSocketRequest(r *http.Request) bool

IsWebSocketRequest returns a boolean indicating whether the request has the headers of a WebSocket handshake request.

func SubscribeURLToNats

func SubscribeURLToNats(method string, urlPath string) string

SubscribeURLToNats buils the subscription channel name with placeholders (started with ":"). The placeholders are than used to obtain path variables

func URLToNats

func URLToNats(method string, urlPath string) string

URLToNats builds the channel name from an URL and Method of http.Request

Types

type Connector

type Connector interface {
	Subscribe(url string, handler NatsHandler)
	UnSubscribe(url string, handler NatsHandler)
}

Connector is the interface for generic pub/sub client.

type Context

type Context struct {
	Request     *Request
	Response    *Response
	RequestForm url.Values
	// contains filtered or unexported fields
}

Context wraps the processed request/response

func (*Context) Abort

func (c *Context) Abort()

Abort abortsthe request that it won's be processed further

func (*Context) AbortWithJSON

func (c *Context) AbortWithJSON(obj interface{})

AbortWithJSON aborts the request and sets the HTTP status code to 500.

func (*Context) BindJSON

func (c *Context) BindJSON(obj interface{}) error

BindJSON unmarshall the request body to given struct

func (*Context) FormVariable

func (c *Context) FormVariable(name string) string

FormVariable returns the variable from request form if available or empty string if not present.

func (*Context) GetWebsocketID

func (c *Context) GetWebsocketID() (wdsID string, err error)

func (*Context) HeaderVariable

func (c *Context) HeaderVariable(name string) string

HeaderVariable returns the header variable if avalable or empty string if header not present.

func (*Context) IsAborted

func (c *Context) IsAborted() bool

IsAborted returns true if the request in context were aborted by previous middleware

func (*Context) JSON

func (c *Context) JSON(statusCode int, obj interface{})

JSON writes the serialized json to response

func (*Context) ParseForm

func (c *Context) ParseForm() error

ParseForm parses the request to values in RequestForm of the Context. The parsed form also includes the parameters from query and from body. Same as the http.Request, the post params are prior the query.

func (*Context) PathVariable

func (c *Context) PathVariable(name string) string

PathVariable returns the path variable based on its name (:xxx) defined in subscription URL

type HookFunc

type HookFunc func(*Response)

HookFunc is the function that is used to modify response just before its transformed to HTTP response

type NatsClient

type NatsClient struct {
	// contains filtered or unexported fields
}

NatsClient serves as Connector to NATS messaging. Allows to subscribe for an specific url or url pattern.

func NewNatsClient

func NewNatsClient(conn *nats.Conn) (*NatsClient, error)

NewNatsClient creates new NATS client from given connection. The connection must be connected or the function will return error ErrNatsClientNotConnected.

func (*NatsClient) DELETE

func (nc *NatsClient) DELETE(url string, handler NatsHandler)

DELETE subscribes the client for an url with DELETE method.

func (*NatsClient) GET

func (nc *NatsClient) GET(url string, handler NatsHandler)

GET subscribes the client for an url with GET method.

func (*NatsClient) HandleWebsocket

func (nc *NatsClient) HandleWebsocket(webSocketID string, handler nats.MsgHandler)

HandleWebsocket subscribes the handler for specific websocketID. The method adds the specific prefix for client to proxy communication.

func (*NatsClient) POST

func (nc *NatsClient) POST(url string, handler NatsHandler)

POST subscribes the client for an url with POST method.

func (*NatsClient) PUT

func (nc *NatsClient) PUT(url string, handler NatsHandler)

PUT subscribes the client for an url with PUT method.

func (*NatsClient) Send

func (nc *NatsClient) Send(method string, url string, req *Request) (response *Response, err error)

func (*NatsClient) SendDELETE

func (nc *NatsClient) SendDELETE(url string, req *Request) (response *Response, err error)

func (*NatsClient) SendGET

func (nc *NatsClient) SendGET(url string, req *Request) (response *Response, err error)

func (*NatsClient) SendPOST

func (nc *NatsClient) SendPOST(url string, req *Request) (response *Response, err error)

func (*NatsClient) SendPUT

func (nc *NatsClient) SendPUT(url string, req *Request) (response *Response, err error)

func (*NatsClient) Subscribe

func (nc *NatsClient) Subscribe(method, url string, handler NatsHandler)

Subscribe is a generic subscribe function for any http method. It also wraps the processing of the context.

func (*NatsClient) Use

func (nc *NatsClient) Use(middleware NatsHandler)

Use will add the middleware NatsHandler for a client.

func (*NatsClient) WriteWebsocket

func (nc *NatsClient) WriteWebsocket(websocketID string, data []byte) error

WriteWebsocket writes given bytes to given websocket subject.

func (*NatsClient) WriteWebsocketJSON

func (nc *NatsClient) WriteWebsocketJSON(websocketID string, msg interface{}) error

WriteWebsocketJSON writes struct serialized to JSON to registered websocketID NATS subject.

type NatsHandler

type NatsHandler func(c *Context)

NatsHandler handles the tranforrmed HTTP request from NatsProxy. The context c wraps the request and response.

type NatsHandlers

type NatsHandlers []NatsHandler

NatsHandlers is an array of NatsHandler functions. This type primary function is to group filters in NatsClient.

type NatsProxy

type NatsProxy struct {
	// contains filtered or unexported fields
}

NatsProxy serves as a proxy between gnats and http. It automatically translates the HTTP requests to nats messages. The url and method of the HTTP request serves as the name of the nats channel, where the message is sent.

func NewNatsProxy

func NewNatsProxy(conn *nats.Conn) (*NatsProxy, error)

NewNatsProxy creates an initialized NatsProxy

func (*NatsProxy) AddHook

func (np *NatsProxy) AddHook(urlRegex string, hook HookFunc) error

AddHook add the hook to modify, process response just before its transformed to HTTP form.

func (*NatsProxy) ServeHTTP

func (np *NatsProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)

type Request

type Request struct {
	URL         string             `protobuf:"bytes,1,opt,name=URL,json=uRL" json:"URL,omitempty"`
	Method      string             `protobuf:"bytes,2,opt,name=Method,json=method" json:"Method,omitempty"`
	RemoteAddr  string             `protobuf:"bytes,3,opt,name=RemoteAddr,json=remoteAddr" json:"RemoteAddr,omitempty"`
	Body        []byte             `protobuf:"bytes,4,opt,name=Body,json=body,proto3" json:"Body,omitempty"`
	Form        map[string]*Values `` /* 138-byte string literal not displayed */
	Header      map[string]*Values `` /* 144-byte string literal not displayed */
	WebSocketID string             `protobuf:"bytes,7,opt,name=WebSocketID,json=webSocketID" json:"WebSocketID,omitempty"`
}

func NewRequest

func NewRequest() *Request

func (*Request) Descriptor

func (*Request) Descriptor() ([]byte, []int)

func (*Request) FromHTTP

func (r *Request) FromHTTP(req *http.Request) error

func (*Request) GetForm

func (r *Request) GetForm() Variables

func (*Request) GetHeader

func (r *Request) GetHeader() Variables

func (*Request) GetWebSocketID

func (r *Request) GetWebSocketID() string

func (*Request) IsWebSocket

func (r *Request) IsWebSocket() bool

func (*Request) ProtoMessage

func (*Request) ProtoMessage()

func (*Request) Reset

func (m *Request) Reset()

func (*Request) String

func (m *Request) String() string

func (*Request) UnmarshallFrom

func (r *Request) UnmarshallFrom(requestData []byte) error

UnmarshallFrom unmarshal the request from bytes, that usually come from proxy.

type RequestPool

type RequestPool struct {
	sync.Pool
}

func NewRequestPool

func NewRequestPool() RequestPool

func (*RequestPool) GetRequest

func (r *RequestPool) GetRequest() *Request

func (*RequestPool) PutRequest

func (r *RequestPool) PutRequest(req *Request)

type Response

type Response struct {
	StatusCode int32              `protobuf:"varint,1,opt,name=StatusCode,json=statusCode" json:"StatusCode,omitempty"`
	Header     map[string]*Values `` /* 144-byte string literal not displayed */
	Body       []byte             `protobuf:"bytes,3,opt,name=Body,json=body,proto3" json:"Body,omitempty"`
	DoUpgrade  bool               `protobuf:"varint,4,opt,name=DoUpgrade,json=doUpgrade" json:"DoUpgrade,omitempty"`
}

func NewResponse

func NewResponse() *Response

NewResponse creates blank initialized Response object.

func (*Response) Descriptor

func (*Response) Descriptor() ([]byte, []int)

func (*Response) GetHeader

func (r *Response) GetHeader() Variables

func (*Response) ProtoMessage

func (*Response) ProtoMessage()

func (*Response) ReadFrom

func (r *Response) ReadFrom(responseData []byte) error

DecodeResponse decodes the marshalled Response struct back to struct.

func (*Response) Reset

func (m *Response) Reset()

func (*Response) String

func (m *Response) String() string

type ResponsePool

type ResponsePool struct {
	sync.Pool
}

func NewResponsePool

func NewResponsePool() ResponsePool

func (*ResponsePool) GetResponse

func (r *ResponsePool) GetResponse() *Response

func (*ResponsePool) PutResponse

func (r *ResponsePool) PutResponse(res *Response)

type Values

type Values struct {
	Arr []string `protobuf:"bytes,1,rep,name=arr" json:"arr,omitempty"`
}

func (*Values) Descriptor

func (*Values) Descriptor() ([]byte, []int)

func (*Values) ProtoMessage

func (*Values) ProtoMessage()

func (*Values) Reset

func (m *Values) Reset()

func (*Values) String

func (m *Values) String() string

type Variables

type Variables map[string]*Values

func (Variables) Add

func (h Variables) Add(key, value string)

func (Variables) Del

func (h Variables) Del(key string)

func (Variables) Get

func (h Variables) Get(name string) string

func (Variables) Set

func (h Variables) Set(key, val string)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL