restful

package module
v0.0.0-...-f1ea2bd Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2023 License: MIT Imports: 22 Imported by: 0

README

jemuelmiao/restful

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

MIT License Go Report Card

Required

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

Installation

Use go get.

go get github.com/jemuelmiao/restful

Then import the package into your own code.

import "github.com/jemuelmiao/restful"

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), 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 table name, with URL params:

    • db: database name, default is restful
    • table: table name, default is {Biz}

    e.g.: /{Biz}?db=dbName&table=tableName

How to use

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

Insert resource (with or without id)

Request:

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

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

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 /student/student-id-001 HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 226

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

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 /student/student-id-001?seq=1 HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 226

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

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 /student/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 /student/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": "jemuelmiao",
        ...
    }
}
Get resources

Request:

GET /student?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": "jemuelmiao",
                ...
            },
            {
                "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)
)

A set of supported Field Kind

Variables

This section is empty.

Functions

func CheckBool

func CheckBool(v interface{}) interface{}

CheckBool check v type if v is BOOL, return v if v is not BOOL, return nil

func CheckFloat

func CheckFloat(value interface{}) interface{}

CheckFloat check value type if value is any type represent FLOAT, return FLOAT64 value if value is not any type represent FLOAT, return nil

func CheckInt

func CheckInt(value interface{}) interface{}

CheckInt check value type if value is any type represent INT, return INT64 value if value is not any type represent INT, return nil

func CheckObject

func CheckObject(value interface{}) interface{}

CheckObject check value type if value is OBJECT, return its value if value is not OBJECT, return nil

func CheckString

func CheckString(value interface{}) interface{}

CheckString check value type if value is any type represent STRING, return STRING value if value is not any type represent STRING, return nil

func CheckUint

func CheckUint(value interface{}) interface{}

CheckUint check value type if value is any type represent UINT, return UINT64 value if value is not any type represent UINT, return nil

func EmptyValue

func EmptyValue(kind uint) interface{}

EmptyValue get the default value of kind

func GenUniqueID

func GenUniqueID() string

GenUniqueID is an function to gen a unique id with STRING type support objectid or uuid

func GetString

func GetString(s interface{}) string

GetString check s type if s is String, return its value if s is not STRING, return empty string

func GetStringD

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

GetStringD check s type if s is String, return its value if s is not STRING, return default d

func Init

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

Init is a function to init restful service

func IsEmpty

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

IsEmpty check value is nin or default value of its kind

func IsEmptyArray

func IsEmptyArray(value interface{}) bool

IsEmptyArray check whether value is empty if value is nil or empty array, return true

func IsEmptyBool

func IsEmptyBool(value interface{}) bool

IsEmptyBool check whether value is empty if value is nil or default value of bool, return true

func IsEmptyNumber

func IsEmptyNumber(value interface{}) bool

IsEmptyNumber check whether value is empty if value is nil or default value of float64, return true

func IsEmptyObject

func IsEmptyObject(value interface{}) bool

IsEmptyObject check whether value is empty if value is nil or empty object, return true

func IsEmptyString

func IsEmptyString(value interface{}) bool

IsEmptyString check whether value is empty if value is nil or default value of string, return true

func ParseKindArray

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

ParseKindArray parse all array kind of value

func ParseKindMap

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

ParseKindMap parse map kind of value

func ParseKindValue

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

ParseKindValue parse all kind of value

func RandString

func RandString(n int) string

RandString is an function to gen a rand string

func Register

func Register(method, pattern string, h Handler)

Register is a function to register handler to http mux

func RemoveDupArray

func RemoveDupArray(s []string) []string

RemoveDupArray remove duplicate elements

Types

type ExtLog

type ExtLog struct {
	Logger *log.Logger
}

ExtLog is the default Logger

func (*ExtLog) Debugf

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

Debugf prints debug log

func (*ExtLog) Debugln

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

Debugln prints debug log with a newline appended

func (*ExtLog) Fatalf

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

Fatalf prints fatal log

func (*ExtLog) Fatalln

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

Fatalln prints fatal log with new line

func (*ExtLog) Warnf

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

Warnf prints warn log

func (*ExtLog) Warnln

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

Warnln prints warn log with new line

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
}

Field definition

type FieldSet

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

FieldSet is a structure to store DataStruct fields parsing result

func BuildFieldSet

func BuildFieldSet(typ reflect.Type) *FieldSet

BuildFieldSet is a function to parsing the DataStruct

func (*FieldSet) BuildAllObj

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

BuildAllObj build the condition of `all` filter

func (*FieldSet) BuildFilterObj

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

BuildFilterObj build the condition like `WHERE f1 = xxx AND ...` in SQL

func (*FieldSet) BuildInObj

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

BuildInObj build the condition of `in` filter

func (*FieldSet) BuildNinObj

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

BuildNinObj build the condition of `nin` filter

func (*FieldSet) BuildOrObj

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

BuildOrObj build the condition of `or` filter

func (*FieldSet) BuildOrderArray

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

BuildOrderArray build sort

func (*FieldSet) BuildRangeObj

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

BuildRangeObj build the condition of `range` filter

func (*FieldSet) BuildRegexSearchObj

func (fs *FieldSet) BuildRegexSearchObj(search string, regexSearchFields []string, cond map[string]interface{}) error

BuildRegexSearchObj build the condition of `regex search` filter

func (*FieldSet) BuildSearchContent

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

BuildSearchContent concat the text according to the search fields

func (*FieldSet) BuildSelectObj

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

BuildSelectObj build the select fields

func (*FieldSet) CheckIndexFields

func (fs *FieldSet) CheckIndexFields(fields []string) ([]string, error)

CheckIndexFields check the index in the config of Processor valid or not

func (*FieldSet) CheckObject

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

CheckObject check obj is valid or not

func (*FieldSet) CheckRegexSearchFields

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

CheckRegexSearchFields check the search fields in the config of Processor valid or not

func (*FieldSet) CheckSearchFields

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

CheckSearchFields check the search fields in the config of Processor valid or not

func (*FieldSet) InReplace

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

InReplace adapted MongoDB '_id' field

func (*FieldSet) InSort

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

InSort sort data

func (*FieldSet) IsFieldCreateOnly

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

IsFieldCreateOnly check field is create only or not

func (*FieldSet) IsFieldMember

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

IsFieldMember check field is a member of Struct or not

func (*FieldSet) IsFieldReadOnly

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

IsFieldReadOnly check field is read only or not

func (*FieldSet) IsMapMember

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

IsMapMember check field is a member of Struct map field or not

func (*FieldSet) OrderArray2Slice

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

OrderArray2Slice convert the sort array to string slice

func (*FieldSet) OutReplace

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

OutReplace adapted MongoDB '_id' field

func (*FieldSet) OutReplaceArray

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

OutReplaceArray adapted MongoDB '_id' field for ARRAY

func (*FieldSet) ParseSimpleArray

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

ParseSimpleArray parse a simple array kind of value

func (*FieldSet) ParseSimpleValue

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

ParseSimpleValue parse a simple kind of value

func (*FieldSet) SetCreateOnlyFields

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

SetCreateOnlyFields set the fields create only

func (*FieldSet) SetReadOnlyFields

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

SetReadOnlyFields set the fields read only

type GlobalConfig

type GlobalConfig struct {
	Mux                *mux.Router  // gorilla/mux
	MgoSess            *mgo.Session // mongodb session
	DefaultDbName      string       // default db name, using "restful" if not setting
	DefaultIdGenerator string       // default id gnerator, objectid or uuid, using objectid 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
}

GlobalConfig is a config to init restful service

type Handler

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

Handler is a template function for Restful Handler

type Index

type Index struct {
	Key    []string // Index key fields; prefix name with dash (-) for descending order
	Unique bool     // Prevent two documents from having the same index key
}

Index describes the definition of an index

type IndexEnsureList

type IndexEnsureList struct {
	sync.Mutex
	// contains filtered or unexported fields
}

IndexEnsureList is a structure describes a list of indices to ensure

func (*IndexEnsureList) Init

func (l *IndexEnsureList) Init() *IndexEnsureList

Init init the IndexEnsureList

func (*IndexEnsureList) Pop

Pop pop an index out of IndexEnsureList

func (*IndexEnsureList) Push

func (l *IndexEnsureList) Push(idx *IndexToEnsureStruct)

Push push an index into IndexEnsureList

type IndexEnsuredMap

type IndexEnsuredMap struct {
	sync.RWMutex
	// key: db|table
	M map[string]int64
}

IndexEnsuredMap cache to store index that has been ensured

func (*IndexEnsuredMap) Exist

func (s *IndexEnsuredMap) Exist(k string) bool

Exist check whether an index exists or not

func (*IndexEnsuredMap) Set

func (s *IndexEnsuredMap) Set(k string)

Set add an index into the cache

type IndexToEnsureStruct

type IndexToEnsureStruct struct {
	DB        string
	Table     string
	Processor *Processor
}

IndexToEnsureStruct defines where and how to create the index

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{})
}

Logger is an interface for logging

var Log Logger

Log is a global log handle you can reassign Log to your own Logger which contains the methods Logger interface contains

type Processor

type Processor struct {
	// Business name, functions:
	//   1. default value of TableName
	//   2. default value of URLPath
	//   3. logs
	Biz string

	// Table name, using ${Biz} if empty
	TableName 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 for search implemented by db regex
	RegexSearchFields []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

	// indexes will be created in database/table
	Indexes []Index

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

	// CURD handler
	PostHandler    Handler
	PutHandler     Handler
	PatchHandler   Handler
	GetHandler     Handler
	GetPageHandler Handler
	DeleteHandler  Handler
	TriggerHandler 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 table name from URL Query
	// e.g.: /path?db=dbName&table=tableName
	// default db name: restful
	// default table name: ${TableName}
	GetDbName    func(query url.Values) string
	GetTableName func(query url.Values) string
}

Processor is a set of configurations and handlers of a Restful resource

func (*Processor) Init

func (p *Processor) Init() error

Init a processor

func (*Processor) Load

func (p *Processor) Load()

Load is a function to register handlers

type Rsp

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

Rsp is a general returning structure for all request

type RspGetPageData

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

RspGetPageData is a general returning structure in `data` field for GetPage request

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 {
				Db      string `json:"db"`
				Table   string `json:"table"`
				Content string `json:"content"`
			} `json:"_source"`
		} `json:"hits"`
	} `json:"hits"`
}

SearchResponse is the rsp structure of es

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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