restful

package module
v0.0.0-...-03f8e43 Latest Latest
Warning

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

Go to latest
Published: Sep 20, 2015 License: MIT Imports: 22 Imported by: 0

README

restful

Build Status GoDoc

Model-driven, RESTful api server framework in golang

Concept and Goals

Model-driven software development (MDSD) is an alternative to round-trip engineering. Round-trip engineering is the concept of being able to make any kind of change to a model as well as to the code generated from that model. The changes always propagate bidirectional and both artifacts are always consistent. The transition from code to model (the reverse engineering) is especially interesting in this context.

By that, it means most source code (interfaces for both client and server) can be generated based on an ontological model which to be more specificed - an API protocol scheme definition in a format such as JSON.

Usage

  1. preparing api's data model
model := map[string]map[string]ServFunc{
	"GET": {
		"/ping": t0.ping,
	},
	"POST": {
		"/foobar/create/{type:.*}": t0.postFoobarCreate,
	},
	"DELETE": {
		"/foobar/{name:.*}": t0.deleteFoobars,
	},
	"OPTIONS": {
		"": t0.optionsHandler,
	},
}
  1. writing server-side implementation

type T struct {}

func (t *T) ping(w http.ResponseWriter, r *http.Request, vars map[string]string, body io.ReadCloser) (int, interface{}, error) {
	w.WriteHeader(http.StatusOK)
	_, err := w.Write([]byte{'O', 'K'})
	return 0, nil, err
}

func (t *T) postFoobarCreate(w http.ResponseWriter, r *http.Request, vars map[string]string, body io.ReadCloser) (int, interface{}, error) {
	var v map[string]int

	err := json.NewDecoder(body).Decode(&v)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	b, err := json.Marshal(v)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	ret := map[string]string{
		"id":   "1",
		"type": vars["type"],
		"form": r.Form.Get("foo"),
		"json": string(b),
	}
	return http.StatusCreated, ret, nil
}

func (t *T) deleteFoobars(w http.ResponseWriter, r *http.Request, vars map[string]string, body io.ReadCloser) (int, interface{}, error) {
	return http.StatusNoContent, nil, nil
}

func (t *T) optionsHandler(w http.ResponseWriter, r *http.Request, vars map[string]string, body io.ReadCloser) (int, interface{}, error) {
	opt := map[string]int{
		"foo": 1,
		"bar": 2,
	}
	return http.StatusOK, opt, nil
}

and begin to serv

cfg := &Config{
	Logging:     true,
	EnableCors:  true,
	CorsHeaders: "*",
	SocketGroup: "nobody",
	TLSConfig:   nil,
}

s := NewServer(cfg)

p := []string{"tcp://:80"}

go func() {
	err := s.Prepare(p, model)
	if err != nil {
		t.Fatalf("Server preparation failed %v", err)
	}
}()

s.AcceptConnections()

defer s.Close()
  1. writing client side
c := NewClient("", "tcp", "127.0.0.1:65436", nil)

r, _, n, err := c.Call("GET", "/ping", nil, nil)

r, _, n, err = c.Call("POST",
	"/foobar/create/foo",
	map[string]int{"foo": 1, "bar": 2},
	map[string][]string{"foo": []string{"bar"}},
)

r, _, n, err = c.Call("DELETE",
	"/foobar/foo",
	nil,
	nil,
)

r, _, n, err = c.Call("OPTIONS",
	"",
	nil,
	nil,
)

Developing

Commited code must pass:

TODO

  • source code generator

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (

	// Version indicate api version
	Version = "1"
)

Functions

func BoolValue

func BoolValue(r *http.Request, k string) bool

func BoolValueOrDefault

func BoolValueOrDefault(r *http.Request, k string, d bool) bool

BoolValueOrDefault returns the default bool passed if the query param is missing, otherwise it's just a proxy to boolValue above

func Int64ValueOrZero

func Int64ValueOrZero(r *http.Request, k string) int64

Types

type Client

type Client struct {

	// default headers
	HTTPDefaultHeaders map[string]string
	// user agent string
	UserAgent string
	// contains filtered or unexported fields
}

Client construct a restful request initiator

func NewClient

func NewClient(keyFile string, proto, addr string, tlsConfig *tls.Config) *Client

func (*Client) Call

func (c *Client) Call(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error)

type Config

type Config struct {
	Logging     bool
	EnableCors  bool
	CorsHeaders string
	SocketGroup string
	TLSConfig   *tls.Config
}

type ServFunc

type ServFunc func(w http.ResponseWriter, r *http.Request, vars map[string]string, body io.ReadCloser) (int, interface{}, error)

type Server

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

func NewServer

func NewServer(cfg *Config) *Server

func (*Server) AcceptConnections

func (s *Server) AcceptConnections()

func (*Server) Close

func (s *Server) Close()

func (*Server) Prepare

func (s *Server) Prepare(protoAddrs []string, m map[string]map[string]ServFunc) error

Prepare loops through all of the protocols sent in to spawns off a go routine to setup a serving http.Server for each.

Jump to

Keyboard shortcuts

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