Help us shape the future of Go! Take the 2026 Go Developer Survey

servicerouter

package module
v0.0.0-...-8e2659d Latest Latest
Warning

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

Go to latest
Published: Feb 15, 2017 License: MIT Imports: 5 Imported by: 1

README

Service Router

A simple transport and schema agnostic router for your services.

Introduction

[TODO] Write This

Why

Am sure like me, you have tried creating service that interact over WebSocket or other transports that don't have idea of routes (eg: Plain TCP).

You probably have also built a service on http and want to switch to RabbitMQ, and now you have to rewrite everything; because you have to subscribe 500 topics for each feature or come up with a scheme to call appropriate methods.

With servicerouter you implement your own scheme which would be portable across transports.

Now you can send

{
  "action":"profile.create",
  "parameters": {
    "firstName": "John",
    "lastName": "Doe",
    "location": "Accra",
    "country": "Ghana"
  }
 }

or

http://service?action=profile.create&firstName=John&lastName=Doe&location=Accra&country=Ghana

And handle all by changing or adding a few lines of code

Getting started
go get github.com/codmajik/servicerouter
sample app
package main

import (
	"fmt"
	sr "github.com/codmajik/servicerouter"
	"golang.org/x/net/context"
	"net/http"
	"strings"
)

func main() {

	// NOTE: The routing scheme used here is arbitrary
	router := sr.NewRouter()

	router.AddRoute( 
		sr.SimpleRoute("home"),
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			return "HOME_CONTENT", nil
		}),
	)

	// use prefix to do subrouting
	subroute := router.AddRoute(
		sr.PrefixRoute("users."),
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			return "USERS_INVALID_OPERATION", nil
		}),
	)

	// the following routes are sub of users, so  users. would have to match first

	// users.list --> fetch all users
	subroute.AddRoute(
		sr.SimpleRoute("list"),
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			return "LIST_OF_USERS", nil
		})
	)

		//users.list //
	subroute.AddRoute(
		sr.Name("List Users by Group Association"),
		sr.PrefixRoute("list.groups/"),
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			return "LIST_OF_USERS_BY_GROUP", nil
		}),
	).AddRoute(
		sr.SimpleRoute("admin"), // you can even subroute on a subroute - META ZEN
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			return "LIST_OF_ADMIN_USERS", nil
		}),
	)

	// users.save
	subroute.AddRoute( 
		sr.SimpleRoute("save"),
		sr.RouteHandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {
			params := req.(map[string]string)
			fmt.Println("save to db", params)
			return "HOUSTON_ALL_IS_WELL", nil
		}),
	)

	http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {

		qpath = strings.Replace(req.RequestURI, "/", ".", -1)

		// result, err := router.Exec(req.Context(), qpath, nil)
		result, err := router.ExecPath(qpath, nil)
		if err != nil {
			rw.Write([]byte("Path Not Found: " + err.Error()))
			return
		}

		if result != nil {
			rw.Write([]byte(result.(string)))
		}
	})

	fmt.Println("Listening for http request on :8080")
	fmt.Println(http.ListenAndServe(":8080", nil))
}


Notes
  • SimpleRoute: don't add sub routes to simple routes, sub routes are only matched after the base match
  • RouteHandlerFunc: match gokit's endpoint.Endpoint and can be composed
Inspired by
Todo
  • More documentation
  • More examples
  • Maybe a tutorial
License

MIT -- See LICENSE file

Documentation

Index

Constants

View Source
const (
	//RouteKey Context value key for provided path
	RouteKey = "sr.Route:Key"

	//RouteName Context value key for provided path
	RouteName = "sr.Route:Name"
)

Variables

View Source
var ErrRouteNotFound = errors.New("Route Not Found")

ErrRouteNotFound route was not found

Functions

This section is empty.

Types

type Handler

type Handler interface {
	Handle(context.Context, interface{}) (interface{}, error)
}

Handler callback on matched route

type HandlerFunc

type HandlerFunc func(context.Context, interface{}) (interface{}, error)

HandlerFunc simplified Handler interface

func (HandlerFunc) Handle

func (f HandlerFunc) Handle(ctx context.Context, req interface{}) (r interface{}, e error)

Handle implementation of RoutedHandler

type OptFn

type OptFn func(*Router)

OptFn option function

func RootPrefix

func RootPrefix(rootPrefix string) OptFn

RootPrefix set rootPrefix for this router this is used to add a universal route that is not part of routing scheme mount the same routing on different roots without changing your scheme

func RouteCallback

func RouteCallback(cb func(string, *Route)) OptFn

RouteCallback called when a route matches with info

type Route

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

Route holds a match

func (*Route) AddRoute

func (r *Route) AddRoute(opts ...RouteOptFn) *Route

AddRoute add a branch to this routing three

func (*Route) Name

func (r *Route) Name() string

Name name of route. just for logging and debuging

type RouteOptFn

type RouteOptFn func(*Route)

func Name

func Name(name string) RouteOptFn

Name set name. for debuging purposes only

func PrefixRoute

func PrefixRoute(prefix string) RouteOptFn

PrefixRoute string prefix matching home. == home.matching

func RegExpRoute

func RegExpRoute(re *regexp.Regexp) RouteOptFn

RegExpRoute regular expression based matching

func RouteHandler

func RouteHandler(f Handler) RouteOptFn

RouteHandler set callback to execute if route matches

func RouteHandlerFunc

func RouteHandlerFunc(f HandlerFunc) RouteOptFn

RouteHandlerFunc set callback to execute if route matches

func SimpleRoute

func SimpleRoute(path string) RouteOptFn

SimpleRoute litral string matching ie: home.matching == home.matching

type Router

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

Router : Service Router

func NewRouter

func NewRouter(opts ...OptFn) *Router

NewRouter Create new router

func (*Router) AddRoute

func (r *Router) AddRoute(opts ...RouteOptFn) *Route

AddRoute add a new route

func (*Router) Clear

func (r *Router) Clear() *Router

Clear remove all configured routes

func (*Router) Exec

func (r *Router) Exec(ctx context.Context, path string, req interface{}) (interface{}, error)

Exec execute routing

func (*Router) ExecPath

func (r *Router) ExecPath(path string, req interface{}) (interface{}, error)

ExecPath route the specified path

func (*Router) RootPrefix

func (r *Router) RootPrefix() string

RootPrefix get root prefix configured for this router

Directories

Path Synopsis
examples
building command

Jump to

Keyboard shortcuts

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