All Projects → pingcap → fn

pingcap / fn

Licence: Apache-2.0 license
No description or website provided.

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to fn

Jsonapi Utils
Build JSON API-compliant APIs on Rails with no (or less) learning curve.
Stars: ✭ 191 (+582.14%)
Mutual labels:  json-api
Datoji
A tiny JSON storage service. Create, Read, Update, Delete and Search JSON data.
Stars: ✭ 222 (+692.86%)
Mutual labels:  json-api
Api Generator
PHP-code generator for Laravel framework, with complete support of JSON-API data format
Stars: ✭ 244 (+771.43%)
Mutual labels:  json-api
Ck Caffe
Collective Knowledge workflow for Caffe to automate installation across diverse platforms and to collaboratively evaluate and optimize Caffe-based workloads across diverse hardware, software and data sets (compilers, libraries, tools, models, inputs):
Stars: ✭ 192 (+585.71%)
Mutual labels:  json-api
Yin
The efficient and elegant JSON:API 1.1 server library for PHP
Stars: ✭ 214 (+664.29%)
Mutual labels:  json-api
Crnk Framework
JSON API library for Java
Stars: ✭ 234 (+735.71%)
Mutual labels:  json-api
Json Api
Implementation of JSON API in PHP 7
Stars: ✭ 171 (+510.71%)
Mutual labels:  json-api
rest-api
Laravel restfull api boilerplate
Stars: ✭ 57 (+103.57%)
Mutual labels:  json-api
Jsonapi Rb
Efficiently produce and consume JSON API documents.
Stars: ✭ 219 (+682.14%)
Mutual labels:  json-api
Jsonapi Rails
Rails gem for fast jsonapi-compliant APIs.
Stars: ✭ 242 (+764.29%)
Mutual labels:  json-api
Aimeos Symfony
Symfony e-commerce bundle for professional, ultra fast online shops, complex B2B applications and #gigacommerce
Stars: ✭ 194 (+592.86%)
Mutual labels:  json-api
Marshmallow Jsonapi
JSON API 1.0 (https://jsonapi.org/) formatting with marshmallow
Stars: ✭ 203 (+625%)
Mutual labels:  json-api
Iotwifi
Raspberry Pi (arm) wifi configuration container. Configure and control wifi connectivity with a JSON based REST api.
Stars: ✭ 236 (+742.86%)
Mutual labels:  json-api
Rpc
Simple RPC style APIs with generated clients & servers.
Stars: ✭ 192 (+585.71%)
Mutual labels:  json-api
Hotels server
酒店预订系统后台管理系统
Stars: ✭ 249 (+789.29%)
Mutual labels:  json-api
Jsonapi Datastore
JavaScript client-side JSON API data handling made easy.
Stars: ✭ 190 (+578.57%)
Mutual labels:  json-api
Json2typescript
Convert JSON to TypeScript with secure type checking!
Stars: ✭ 230 (+721.43%)
Mutual labels:  json-api
druxt.js
The Fully Decoupled Drupal Framework
Stars: ✭ 96 (+242.86%)
Mutual labels:  json-api
TypeScript-in-Nodejs-Starter
A starter kit for Node.js project written with TypeScript.
Stars: ✭ 39 (+39.29%)
Mutual labels:  json-api
Json Apis With Github
🔨 Tool to make Simple and Quick JSON APIs with GitHub.
Stars: ✭ 240 (+757.14%)
Mutual labels:  json-api

fn

This library aims to simplify the construction of JSON API service, fn.Wrap is able to wrap any function to adapt the interface of http.Handler, which unmarshals POST data to a struct automatically.

Benchmark

BenchmarkIsBuiltinType-8                50000000                33.5 ns/op             0 B/op          0 allocs/op
BenchmarkSimplePlainAdapter_Invoke-8     2000000               757 ns/op             195 B/op          3 allocs/op
BenchmarkSimpleUnaryAdapter_Invoke-8     2000000               681 ns/op             946 B/op          5 allocs/op
BenchmarkGenericAdapter_Invoke-8         2000000               708 ns/op             946 B/op          5 allocs/op

Support types

io.ReadCloser      // request.Body
http.Header        // request.Header
fn.Form        // request.Form
fn.PostForm    // request.PostForm
*fn.Form       // request.Form
*fn.PostForm   // request.PostForm
*url.URL           // request.URL
*multipart.Form    // request.MultipartForm
*http.Request      // raw request

Usage

http.Handle("/test", fn.Wrap(test))

func test(io.ReadCloser, http.Header, fn.Form, fn.PostForm, *CustomizedRequestType, *url.URL, *multipart.Form) (*CustomizedResponseType, error)

Examples

Basic

package examples

import (
	"io"
	"mime/multipart"
	"net/http"
	"net/url"

	"github.com/pingcap/fn"
)

type Request struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Response struct {
	Token string `json:"token"`
}

func api1() (*Response, error) {
	return &Response{Token: "token"}, nil
}

func api2(request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api3(rawreq *http.Request, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api4(rawreq http.Header, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api5(form *fn.Form, request *Request) (*Response, error) {
	token := request.Username + request.Password + form.Get("type")
	return &Response{Token: token}, nil
}

func api6(body io.ReadCloser, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api7(form *multipart.Form, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api7(urls *url.URL, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

func api8(urls *url.URL, form *multipart.Form, body io.ReadCloser, rawreq http.Header, request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

Plugins

package examples

import (
	"context"
	"errors"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"

	"github.com/pingcap/fn"
)

var PermissionDenied = errors.New("permission denied")

func logger(ctx context.Context, req *http.Request) (context.Context, error) {
	log.Println("Request", req.RemoteAddr, req.URL.String())
	return ctx, nil
}

func ipWhitelist(ctx context.Context, req *http.Request) (context.Context, error) {
	if strings.HasPrefix(req.RemoteAddr, "172.168") {
		return ctx, PermissionDenied
	}
	return ctx, nil
}

func auth(ctx context.Context, req *http.Request) (context.Context, error) {
	token := req.Header.Get("X-Auth-token")
	_ = token // Validate token (e.g: query db)
	if token != "valid" {
		return ctx, fn.ErrorWithStatusCode(PermissionDenied, http.StatusForbidden)
	}
	return ctx, nil
}

type Request struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Response struct {
	Token string `json:"token"`
}

func example() {
	fn.Plugin(logger, ipWhitelist, auth)
	http.Handle("/api1", fn.Wrap(api1))
	http.Handle("/api2", fn.Wrap(api2))
}

// api1 and api2 request have be validated by `ipWhitelist` and `auth`

func api1() (*Response, error) {
	return &Response{Token: "token"}, nil
}

func api2(request *Request) (*Response, error) {
	token := request.Username + request.Password
	return &Response{Token: token}, nil
}

fn.Group

package examples

import (
	"context"
	"errors"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"

	"github.com/pingcap/fn"
)

var PermissionDenied = errors.New("permission denied")

func logger(ctx context.Context, req *http.Request) (context.Context, error) {
	log.Println("Request", req.RemoteAddr, req.URL.String())
	return ctx, nil
}

func ipWhitelist(ctx context.Context, req *http.Request) (context.Context, error) {
	if strings.HasPrefix(req.RemoteAddr, "172.168") {
		return ctx, PermissionDenied
	}
	return ctx, nil
}

func auth(ctx context.Context, req *http.Request) (context.Context, error) {
	token := req.Header.Get("X-Auth-token")
	_ = token // Validate token (e.g: query db)
	if token != "valid" {
		return ctx, fn.ErrorWithStatusCode(PermissionDenied, http.StatusForbidden)
	}
	return ctx, nil
}

type User struct {
	Balance int64
}

func queryUserFromRedis(ctx context.Context, req *http.Request) (context.Context, error) {
	token := req.Header.Get("X-Auth-token")
	_ = token // Validate token (e.g: query db)
	if token != "valid" {
		return ctx, fn.ErrorWithStatusCode(PermissionDenied, http.StatusForbidden)
	}
	user := &User{
		Balance: 10000, // balance from redis
	}
	return context.WithValue(ctx, "user", user), nil
}

type Response struct {
	Balance int64 `json:"balance"`
}

func example() {
	// Global plugins
	fn.Plugin(logger, ipWhitelist, auth)

	group := fn.NewGroup()

	// Group plugins
	group.Plugin(queryUserFromRedis)
	http.Handle("/user/balance", group.Wrap(fetchBalance))
	http.Handle("/user/buy", group.Wrap(buy))
}

func fetchBalance(ctx context.Context) (*Response, error) {
	user := ctx.Value("user").(*User)
	return &Response{Balance: user.Balance}, nil
}

func buy(ctx context.Context) (*Response, error) {
	user := ctx.Value("user").(*User)
	if user.Balance < 100 {
		return nil, errors.New("please check balance")
	}
	user.Balance -= 100
	return &Response{Balance: user.Balance}, nil
}

ResponseEncoder

package examples

import (
	"context"
	"errors"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"

	"github.com/pingcap/fn"
)

var PermissionDenied = errors.New("permission denied")

func logger(ctx context.Context, req *http.Request) (context.Context, error) {
	log.Println("Request", req.RemoteAddr, req.URL.String())
	return ctx, nil
}

func ipWhitelist(ctx context.Context, req *http.Request) (context.Context, error) {
	if strings.HasPrefix(req.RemoteAddr, "172.168") {
		return ctx, PermissionDenied
	}
	return ctx, nil
}

func auth(ctx context.Context, req *http.Request) (context.Context, error) {
	token := req.Header.Get("X-Auth-token")
	_ = token // Validate token (e.g: query db)
	if token != "valid" {
		return ctx, fn.ErrorWithStatusCode(PermissionDenied, http.StatusForbidden)
	}
	return ctx, nil
}

func injectRequest(ctx context.Context, req *http.Request) (context.Context, error) {
	return context.WithValue(ctx, "_rawreq", req), nil
}

type User struct {
	Balance int64
}

func queryUserFromRedis(ctx context.Context, req *http.Request) (context.Context, error) {
	token := req.Header.Get("X-Auth-token")
	_ = token // Validate token (e.g: query db)
	if token != "valid" {
		return ctx, fn.ErrorWithStatusCode(PermissionDenied, http.StatusForbidden)
	}
	user := &User{
		Balance: 10000, // balance from redis
	}
	return context.WithValue(ctx, "user", user), nil
}

type Response struct {
	Balance int64 `json:"balance"`
}

type ResponseMessage struct {
	Code int         `json:"code"`
	Data interface{} `json:"data"`
}

type ErrorMessage struct {
	Code  int    `json:"code"`
	Error string `json:"error"`
}

func example() {
	// Global plugins
	fn.Plugin(logger, ipWhitelist, auth, injectRequest)
	// Uniform all responses
	fn.SetErrorEncoder(func(ctx context.Context, err error) interface{} {
		req := ctx.Value("_rawreq").(*http.Request)
		log.Println("Error occurred: ", req.URL, err)
		return &ErrorMessage{
			Code:  -1,
			Error: err.Error(),
		}
	})

	fn.SetResponseEncoder(func(ctx context.Context, payload interface{}) interface{} {
		return &ResponseMessage{
			Code: 1,
			Data: payload,
		}
	})

	group := fn.NewGroup()

	// Group plugins
	group.Plugin(queryUserFromRedis)
	http.Handle("/user/balance", group.Wrap(fetchBalance))
	http.Handle("/user/buy", group.Wrap(buy))
}

func fetchBalance(ctx context.Context) (*Response, error) {
	user := ctx.Value("user").(*User)
	return &Response{Balance: user.Balance}, nil
}

func buy(ctx context.Context) (*Response, error) {
	user := ctx.Value("user").(*User)
	if user.Balance < 100 {
		return nil, errors.New("please check balance")
	}
	user.Balance -= 100
	return &Response{Balance: user.Balance}, nil
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].