restful

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 2, 2020 License: MIT Imports: 18 Imported by: 0

README

jimdn/restful

A package based on Golang and MongoDB for quickly building HTTP RESTful services with JSON.

MIT License Go Report Card

Required

  • go 1.10+
  • mongodb v3.4.x v3.6.x
  • elasticsearch v6.7 v7.x (if enable searching)

Dependencies

  • github.com/gorilla/mux
  • github.com/globalsign/mgo
  • github.com/nu7hatch/gouuid

Feature Overview

  • Define the structure of the data resource (including json and bson tags), then you can implement the CURD service of HTTP+JSON. The protocol is as follows:
HTTP Method Path URL Params HTTP Body Explain
POST /{biz} - data to be inserted insert data
PUT /{biz}/{id} - data to be upserted insert or update(overwrite) data by id
PATCH /{biz}/{id} seq data to be updated update data by id
DELETE /{biz}/{id} - - delete data by id
GET /{biz}/{id} - - get data by id
GET /{biz} page
size
filter
range
in
nin
all
search
order
select
- get list of data:
page=1
size=10
filter={"star":5, "city":"shenzhen"}
range={"age":{"gt":20, "lt":40}}
in={"color":["blue", "red"]}
nin={"color":["blue", "red"]}
all={"color":["blue", "red"]}
search=hello
order=["+age", "-time"]
select=["id", "name", "age"]
  • When defining a data resource structure, the supported data types include:

    common types: bool int32 uint32 int64 uint64 float32 float64 string struct
    array types: []bool []int32 []uint32 []int64 []uint64 []float32 []float64 []string []struct
    map types: map[string]bool map[string]int32 map[string]uint32 map[string]int64 map[string]uint64 map[string]float32 map[string]float64 map[string]string  map[string]struct
    
  • Support field level CreateOnly or ReadOnly:

    • CreateOnly: only allows creation, does not allow subsequent modification of the field
    • ReadOnly: only allows reading, does not allow creation and modification, is suitable for importing data from other systems to the database, and then providing data reading services.
  • With the field check function, the incoming data field type is wrong or does not exist, it will return a failure and prompt specific error information.

  • Support custom data ID or automatically create ID (UUIDv4), BTW, pay attention to the writing of tags:

      type Foo struct {
          Id  *string  `json:"id,omitempty" bson:"_id,omitempty"`
          ...
      }
    
  • Support tracking data birth time and modify time, two additional fields required:

    • btime: birth time, record the timestamp when data created
    • mtime: modify time, record the timestamp the last modification of data
  • Support anti-concurrent writing, the seq field required:

    • seq: will be updated each time the data is modified, the update (PATCH) request needs to bring the data original seq to prevent concurrent writing from causing data confusion.
  • Support custom database name and collection name, with URL params:

    • db: database name, default is rest_{Biz}
    • col: collection name, default is cn

    e.g.: /{Biz}?db=dbName&col=colName

How to use

See examples. We take the Student of simple.go as an example:

Insert resource (with or without id)

Request:

POST /students HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 226

{
    "id": "student-id-001",
    "name": "jimmydeng",
    ...
}

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 91

{
    "code": 0,
    "msg": "post ok",
    "data": {
        "id": "student-id-001"
    }
}
Upsert resource by id

Request:

PUT /students/student-id-001 HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 226

{
    "id": "student-id-001",
    "name": "jimmydeng",
    ...
}

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 90

{
    "code": 0,
    "msg": "put ok",
    "data": {
        "id": "student-id-001"
    }
}
Update resource by id

Request:

PATCH /students/student-id-001?seq=1 HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 226

{
    "id": "student-id-001",
    "name": "jimmydeng02",
    ...
}

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 30

{
    "code": 0,
    "msg": "patch ok",
    "data": {
        "id": "student-id-001"
    }
}
Delete resource by id

Request:

DELETE /students/student-id-001 HTTP/1.1

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 30

{
    "code": 0,
    "msg": "delete ok",
    "data": {
        "id": "student-id-001"
    }
}
Get resource by id

Request:

GET /students/student-id-001 HTTP/1.1

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 537

{
    "code": 0,
    "msg": "get ok",
    "data": {
        "id": "student-id-001"
        "name": "jimmydeng",
        ...
    }
}
Get resources

Request:

GET /students?page=1&size=10 HTTP/1.1

Response:

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2019 06:46:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 797

{
    "code": 0,
    "msg": "get page ok",
    "data": {
        "total": 238,
        "hits": [
            {
                "id": "student-id-001",
                "name": "jimmydeng",
                ...
            },
            {
                "id": "student-id-002",
                "name": "tonywho",
                ...
            }
            ...
        ]
    }
}

Documentation

Index

Constants

View Source
const (
	KindInvalid     = uint(reflect.Invalid)
	KindBool        = uint(reflect.Bool)
	KindInt         = uint(reflect.Int64)
	KindUint        = uint(reflect.Uint64)
	KindFloat       = uint(reflect.Float64)
	KindString      = uint(reflect.String)
	KindObject      = uint(reflect.Struct)
	KindSimpleEnd   = uint(999)
	KindArrayBase   = uint(1000)
	KindArrayBool   = KindArrayBase + KindBool
	KindArrayInt    = KindArrayBase + KindInt
	KindArrayUint   = KindArrayBase + KindUint
	KindArrayFloat  = KindArrayBase + KindFloat
	KindArrayString = KindArrayBase + KindString
	KindArrayObject = KindArrayBase + KindObject
	KindArrayEnd    = uint(1999)
	KindMapBase     = uint(2000)
	KindMapBool     = KindMapBase + KindBool
	KindMapInt      = KindMapBase + KindInt
	KindMapUint     = KindMapBase + KindUint
	KindMapFloat    = KindMapBase + KindFloat
	KindMapString   = KindMapBase + KindString
	KindMapObject   = KindMapBase + KindObject
	KindMapEnd      = uint(2999)
)

Variables

This section is empty.

Functions

func CheckBool

func CheckBool(value interface{}) interface{}

func CheckFloat

func CheckFloat(value interface{}) interface{}

func CheckInt

func CheckInt(value interface{}) interface{}

func CheckObject

func CheckObject(value interface{}) interface{}

func CheckString

func CheckString(value interface{}) interface{}

func CheckUint

func CheckUint(value interface{}) interface{}

func EmptyValue

func EmptyValue(kind uint) interface{}

func EsEnsureIndex

func EsEnsureIndex(indexCfg string) error

func EsRemove

func EsRemove(biz, id string) error

func EsSearch

func EsSearch(biz, search string, size, offset int) ([]string, error)

func EsUpsert

func EsUpsert(biz, id, content string) error

func GenSeq

func GenSeq(n int64) string

func GetString

func GetString(s interface{}) string

func GetStringD

func GetStringD(s interface{}, d string) string

func HttpDo

func HttpDo(url, host, method string, header map[string]string, body []byte) (int, []byte, error)

func Init

func Init(cfg *GlobalConfig, processors *[]Processor) error

func InitEsParam

func InitEsParam(url, user, pwd, index, analyzer, searchAnalyzer string) error

func IsEmpty

func IsEmpty(d interface{}, kind uint) bool

func IsEmptyArray

func IsEmptyArray(d interface{}) bool

func IsEmptyBool

func IsEmptyBool(d interface{}) bool

func IsEmptyNumber

func IsEmptyNumber(d interface{}) bool

func IsEmptyObject

func IsEmptyObject(d interface{}) bool

func IsEmptyString

func IsEmptyString(d interface{}) bool

func NextSeq

func NextSeq(seq string) (string, error)

func ParseKindArray

func ParseKindArray(value []interface{}, kind uint) interface{}

func ParseKindMap

func ParseKindMap(value map[string]interface{}, kind uint) interface{}

func ParseKindValue

func ParseKindValue(value interface{}, kind uint) interface{}

func Register

func Register(method, pattern string, h Handler)

func RemoveDupArray

func RemoveDupArray(s []string) []string

func UUID

func UUID() string

Types

type ExtLog

type ExtLog struct {
	Logger *log.Logger
}

default Logger

func (*ExtLog) Debugf

func (l *ExtLog) Debugf(format string, v ...interface{})

func (*ExtLog) Debugln

func (l *ExtLog) Debugln(v ...interface{})

func (*ExtLog) Fatalf

func (l *ExtLog) Fatalf(format string, v ...interface{})

func (*ExtLog) Fatalln

func (l *ExtLog) Fatalln(v ...interface{})

func (*ExtLog) Warnf

func (l *ExtLog) Warnf(format string, v ...interface{})

func (*ExtLog) Warnln

func (l *ExtLog) Warnln(v ...interface{})

type Field

type Field struct {
	Kind       uint // field's kind
	CreateOnly bool // field can only be written when creating by POST or PUT
	ReadOnly   bool // field can not be written or update, data should be loaded into DB by other ways
}

type FieldSet

type FieldSet struct {
	FMap map[string]Field // fields map
	FSli []string         // fields ordered
}

func BuildFieldSet

func BuildFieldSet(typ reflect.Type) *FieldSet

func (*FieldSet) BuildAllObj

func (fs *FieldSet) BuildAllObj(all map[string]interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildFilterObj

func (fs *FieldSet) BuildFilterObj(filter map[string]interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildInObj

func (fs *FieldSet) BuildInObj(in map[string]interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildNinObj

func (fs *FieldSet) BuildNinObj(nin map[string]interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildOrObj

func (fs *FieldSet) BuildOrObj(or []interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildOrderArray

func (fs *FieldSet) BuildOrderArray(order []string, sort *bson.D) error

func (*FieldSet) BuildRangeObj

func (fs *FieldSet) BuildRangeObj(rang map[string]interface{}, cond map[string]interface{}) error

func (*FieldSet) BuildSearchContent

func (fs *FieldSet) BuildSearchContent(obj map[string]interface{}, fields []string) string

func (*FieldSet) BuildSelectObj

func (fs *FieldSet) BuildSelectObj(slice []string, sel map[string]interface{}) error

func (*FieldSet) CheckObject

func (fs *FieldSet) CheckObject(obj map[string]interface{}, dotOk bool) error

func (*FieldSet) CheckSearchFields

func (fs *FieldSet) CheckSearchFields(fields []string) error

func (*FieldSet) InReplace

func (fs *FieldSet) InReplace(value *map[string]interface{})

func (*FieldSet) InSort

func (fs *FieldSet) InSort(data *map[string]interface{}) bson.D

func (*FieldSet) IsFieldCreateOnly

func (fs *FieldSet) IsFieldCreateOnly(field string) bool

func (*FieldSet) IsFieldMember

func (fs *FieldSet) IsFieldMember(field string) (uint, bool)

func (*FieldSet) IsFieldReadOnly

func (fs *FieldSet) IsFieldReadOnly(field string) bool

func (*FieldSet) IsMapMember

func (fs *FieldSet) IsMapMember(field string) (uint, bool)

func (*FieldSet) OrderArray2Slice

func (fs *FieldSet) OrderArray2Slice(sort *bson.D) []string

func (*FieldSet) OutReplace

func (fs *FieldSet) OutReplace(value *map[string]interface{})

func (*FieldSet) OutReplaceArray

func (fs *FieldSet) OutReplaceArray(values []interface{})

func (*FieldSet) ParseSimpleArray

func (fs *FieldSet) ParseSimpleArray(value interface{}, kind uint) interface{}

func (*FieldSet) ParseSimpleValue

func (fs *FieldSet) ParseSimpleValue(value interface{}, kind uint) interface{}

func (*FieldSet) SetCreateOnlyFields

func (fs *FieldSet) SetCreateOnlyFields(fields []string)

func (*FieldSet) SetReadOnlyFields

func (fs *FieldSet) SetReadOnlyFields(fields []string)

type GlobalConfig

type GlobalConfig struct {
	Mux                *mux.Router  // gorilla/mux
	MgoSess            *mgo.Session // mongodb session
	MgoDefaultDbPrefix string       // mongodb default db prefix, using "rest_" if not setting
	MgoDefaultCol      string       // mongodb default collection name, using "cn" if not setting
	EsEnable           bool         // enable es for search
	EsUrl              string       // es url, default: http://127.0.0.1:9200
	EsUser             string       // es username
	EsPwd              string       // es password
	EsIndex            string       // es index, default: restful
	EsAnalyzer         string       // default: ik_max_word
	EsSearchAnalyzer   string       // default: ik_max_word
}

type Handler

type Handler func(vars map[string]string, query url.Values, body []byte) *Rsp

type Logger

type Logger interface {
	Debugf(format string, v ...interface{})
	Debugln(v ...interface{})
	Warnf(format string, v ...interface{})
	Warnln(v ...interface{})
	Fatalf(format string, v ...interface{})
	Fatalln(v ...interface{})
}
var Log Logger

you can reassign Log to your own Logger which contains the methods above

type Processor

type Processor struct {
	// Business name, usually using plural noun, the uses are as follows:
	//   1. default db name: rest_{Biz}
	//   2. value of elasticsearch biz field
	//   3. logs
	Biz string

	// URL Path as service, usually equal to Biz
	URLPath string

	// for fields type parsing
	DataStruct interface{}

	// fields for search
	// to use the search feature, you must enable GlobalConfig.EsEnable
	// field's type must be string or []string
	SearchFields []string

	// fields CreateOnly
	// fields can only be written when creating by POST or PUT
	CreateOnlyFields []string

	// fields ReadOnly
	// fields can not be written or update, data should be loaded into DB by other ways
	ReadOnlyFields []string

	// fields type and R/W config
	FieldSet *FieldSet

	// CURD handler
	PostHandler    Handler
	PutHandler     Handler
	PatchHandler   Handler
	GetHandler     Handler
	GetPageHandler Handler
	DeleteHandler  Handler

	// Do something after data write success
	//   1. update search data to es
	OnWriteDone func(method string, vars map[string]string, query url.Values, data map[string]interface{})

	// specify db and collection name from URL Query
	// e.g.: /path?db=dbName&col=colName
	// default db name: rest_{Biz}
	// default col name: cn
	GetDbName  func(query url.Values) string
	GetColName func(query url.Values) string
}

func (*Processor) DefaultDelete

func (p *Processor) DefaultDelete() Handler

func (*Processor) DefaultGet

func (p *Processor) DefaultGet() Handler

func (*Processor) DefaultGetColName

func (p *Processor) DefaultGetColName() func(query url.Values) string

func (*Processor) DefaultGetDbName

func (p *Processor) DefaultGetDbName() func(query url.Values) string

func (*Processor) DefaultGetPage

func (p *Processor) DefaultGetPage() Handler

func (*Processor) DefaultOnWriteDone

func (p *Processor) DefaultOnWriteDone() func(method string, vars map[string]string, query url.Values, data map[string]interface{})

func (*Processor) DefaultPatch

func (p *Processor) DefaultPatch() Handler

func (*Processor) DefaultPost

func (p *Processor) DefaultPost() Handler

func (*Processor) DefaultPut

func (p *Processor) DefaultPut() Handler

func (*Processor) Init

func (p *Processor) Init() error

func (*Processor) Load

func (p *Processor) Load()

type Rsp

type Rsp struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data,omitempty"`
}

type RspGetPageData

type RspGetPageData struct {
	Total int64         `json:"total"`
	Hits  []interface{} `json:"hits"`
}

type SearchResponse

type SearchResponse struct {
	Result string `json:"result"`
	Error  struct {
		Type   string `json:"type"`
		Reason string `json:"reason"`
	} `json:"error"`
	Hits struct {
		Total int64 `json:"total"`
		Hits  []struct {
			Id     string `json:"_id"`
			Source struct {
				Biz     string `json:"biz"`
				Content string `json:"content"`
			} `json:"_source"`
		} `json:"hits"`
	} `json:"hits"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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