rubik

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2020 License: Apache-2.0 Imports: 31 Imported by: 7

README

Rubik

An efficient, scalable Web Framework

Homepage - API Documentation

For writing REST client and server-side applications faster. It provides a pluggable layer of abstraction over net/http and enables automation of development environment through extensive tooling.

Even though the goal of Rubik is set it'll take a lot of time to achieve it, that being said you must not use this framework for any production use yet. There can be a lot of edge cases missed and bug fixes beyond the grasps which needs to be fixed before it is production ready.

Framework Components
Quickstart
  • Install Rubik CLI (supports Linux and OSX 64-bit versions only)
curl https://rubik.ashishshekar.com/install | sh
  • Create a new project
okrubik create
  • Change directory to your project name & run the project
cd ${project}
okrubik run
Questions

Co-ordination with suggestions, opinions and questions can be done through this
Mailing list

Contributing

We encourage you to read this Contributing to Rubik Guidelines for ensuring smooth development flow.

Core Goals
  • Make Rubik fun to work with!
  • Provide a great tooling for Rubik
  • Make client-server development easier in Go
  • Concurrent messgage passing
Things Rubik can't do yet

Here is the list of things that rubik can't do yet and needs fixing/development in these areas.

License

Rubik is released under the Apache 2.0 License

Documentation

Overview

Package rubik is used for accessing Rubik Framework: a minimal and efficient web framework for Go and it's APIs.

Running an empty server:

package main

import r "github.com/rubikorg/rubik"

func main() {
	// this runs Rubik server on port: 8000
	panic(r.Run())
}

Adding a route:

package main

import r "github.com/rubikorg/rubik"

func main() {
	// this runs Rubik server on port: 8000
	index := rubik.Route{
		Path: "/",
		Controller: func (req *r.Request) { req.Respond("This is a text response") },
	}
	rubik.UseRoute(index)
	panic(r.Run())
}

Index

Examples

Constants

View Source
const (
	// GET method
	GET = "GET"
	// POST method
	POST = "POST"
	// PUT method
	PUT = "PUT"
	// DELETE method
	DELETE = "DELETE"
)
View Source
const (
	// Version of rubik
	Version = "0.2.0"
)

Variables

View Source
var Content = struct {
	Header     string
	JSON       string
	Text       string
	HTML       string
	URLEncoded string
	Multipart  string
}{
	"Content-Type",
	"application/json",
	"text/plain",
	"text/html",
	"application/x-www-form-urlencoded",
	"multipart/form-data",
}

Content is a struct that holds default values of Content-Type headers it can be used throughout your rubik application for avoiding basic spell mistakes

View Source
var Dispatch = MessagePasser{
	Message: make(chan Message),
	Error:   make(chan error),
}

Dispatch is topic dispatcher of rubik server

View Source
var Storage = StorageContainer{
	// contains filtered or unexported fields
}

Storage is the Container Access of your storage/ folder

View Source
var Type = struct {
	HTML         ByteType
	JSON         ByteType
	Text         ByteType
	Bytes        ByteType
	templateHTML ByteType
	templateText ByteType
}{1, 2, 3, 4, 5, 6}

Type is a rubik type literal used for indication of response/template types

Functions

func AfterRequest

func AfterRequest(h RequestHook)

AfterRequest is used to execute the request hook h after completion of the request. A request is said to be complete only after the response is written through http.ResponseWriter interface of http.Server.

func Attach

func Attach(symbol string, b Block)

Attach a block to rubik tree

func AttachAfter

func AttachAfter(symbol string, b Block)

AttachAfter attaches blocks after boot sequence of routes are complete

func BeforeRequest

func BeforeRequest(h RequestHook)

BeforeRequest is used to execute the request hook h. When a request is sent on a certain route the hook specified as h is executed in a separate goroutine without hindering the current main goroutine of request.

func E

func E(msg string) error

E wraps the message into an error interface and returns it. This method can be used in your controller for throwing error response.

NOTE: this error is not stdlib errors package this is pkg/errors error wrapper

Example
package main

import (
	"github.com/rubikorg/rubik"
)

func main() {
	r := rubik.Route{
		Path: "/test",
		Controller: func(req *rubik.Request) {
			req.Throw(403, rubik.E("invalid token or something"))
		},
	}
	rubik.UseRoute(r)
}
Output:

func GetConfig

func GetConfig() interface{}

GetConfig returns the injected config from the Load method

func GetStorageContainers

func GetStorageContainers() []string

GetStorageContainers returns the names of containers present in your storage/ folder. You can access them by calling `Storage.Access` API and use Get or Put to work with your files.

func Load

func Load(config interface{}) error

Load method loads the config/RUBIK_ENV.toml file into the interface given

func Run

func Run(args ...string) error

Run will make sure all dependencies are met, resolves config and it's conflicts with respect to the RUBIC_ENV passed while executing. It boots all your blocks, middlewares message passing channels and port resolution; before starting the server. If this method does not find PORT that is passed as the first argument or the config/*RUBIC_ENV.toml then it startes at :8000.

func Rx

func Rx(blockName string, topic string, entity interface{}, fn Controller)

Rx is recieving method of rubik which register's recievers for a specific topic and and handles the execution of the reciever on evaluating a message from the source using the controller passed as the parameter

func SetDep added in v0.2.1

func SetDep(any interface{})

SetDep stores your global level dependencies in Rubik Please note that this function is not to be used for setting any volatile intefaces{} that can change in any given time which can create race conditions. This method is only used for static one time inited dependencies such as logger, Connection pool etc..

func SetNotFoundHandler

func SetNotFoundHandler(h http.Handler)

SetNotFoundHandler sets custom 404 handler

func T

func T(block string, topic string) string

T returns the tag for your receiver when you describe it in Rx() method Tag is always defined as

BlockName : Topic string If BlockName is empty string then the tag uses "int" (internal) Denoting that the message is used for internal server purposes

func Tx

func Tx(blockName string, target string, body interface{})

Tx is rubik's transmission method from which is intended to transmit the information from one place to another depending upon the information specified inside the target paramater

func Use

func Use(router Router)

Use ...

func UseRoute

func UseRoute(route Route)

UseRoute is like rubik.Use() but attaches your route to the index Router

Types

type App

type App struct {
	CurrentURL string
	RouteTree
	// contains filtered or unexported fields
}

App is a sandboxed object used by the external blocks of code to access some risk-free part of your rubik server For example: App do not have full access to your project config but it has the ability to decode the config that it needs for only this block of code to work

func (*App) Config

func (sb *App) Config(name string) interface{}

Config get config by name

func (*App) Decode

func (sb *App) Decode(name string, target interface{}) error

Decode decodes the internal rubik server config into the struct that you provide. It returns error if the config is not unmarshalable OR there if there is no config initialized by the given name parameter

type AuthorizationGuard

type AuthorizationGuard interface {
	// Require specifies the config requirement of your Guard
	// this method must return the name of the config that is
	// to be checked before setting the WWW-Authenticate header
	Require() string
	// Require must return the value of the realm to be set
	// inside WWW-Authenticate header header
	GetRealm() string
	// Authorize holds the main authorization logic for a given guard
	// NOTE: Rubik does not proceed with the request if this
	// method returns an error. The error will denote HTTP Status: 401
	Authorize(*App, http.Header) error
}

AuthorizationGuard defines the requirement of a rubik route guard Guards are generally used to negate the request, eg: JWT, ACL etc.. The implementation for a guard should be transparent with specifiction of realm and config requirement. For more information take a look at the BasicGuard implementation here: https://github.com/rubikorg/blocks/blob/master/guard/basic.go

type BlankRequestEntity

type BlankRequestEntity struct {
	Entity
}

BlankRequestEntity ...

type Block

type Block interface {
	OnAttach(*App) error
}

Block is an interface that can be implemented to provide extended functionalities to rubik server Think of it as a plugin which can be attached to the rubik server and can be accessible throughout the lifecycle of rubik server.

A Block can also be thought of as a dependency injected plugin and can be accessed in your controllers by calling rubik.GetBlock('BLOCK_NAME'). Blocks requires you to implement a method called OnAttach. This method is called during rubik server bootstrapper is run and requires you to return an error if any complexity arrises in for your block to function

func GetBlock

func GetBlock(symbol string) Block

GetBlock returns the block that is attached to rubik represented by the symbol supplied as the parameter

type ByteResponse

type ByteResponse struct {
	Status int
	Data   interface{}
	OfType ByteType
	Error  error
	// contains filtered or unexported fields
}

ByteResponse is the response of rubik server

func RenderContent

func RenderContent(btype ByteType, vars interface{}, paths ...string) ByteResponse

RenderContent returns you the response bytes of the target paths that is going to be written on the wire. It is an abstraction of Render method which is used as a layered method inside Render method.

type ByteType

type ByteType int

ByteType let's rubik know what type of bytes to send as response

type Client

type Client struct {
	Debug       bool
	JWTSecret   string
	BasicSecret string
	BearerName  string
	UserAgent   string
	// contains filtered or unexported fields
}

Client is the implementation for rubik project to create a common abstraction of HTTP calls by passing defined entity

func NewClient

func NewClient(baseURL string, timeout time.Duration) *Client

NewClient creates a new instance of ink client

func (*Client) Delete

func (c *Client) Delete(entity interface{}) (Response, error)

Delete ...

func (*Client) Download

func (c *Client) Download(entity DownloadRequestEntity) ([]byte, error)

Download method downloads file from an url from your specified Entity->Route to TargetFilePath passed to the entity

func (*Client) Get

func (c *Client) Get(entity interface{}) (Response, error)

Get ...

func (*Client) Post

func (c *Client) Post(entity interface{}) (Response, error)

Post ...

func (*Client) Put

func (c *Client) Put(entity interface{}) (Response, error)

Put ...

type Communicator

type Communicator interface {
	Send(string, interface{}) error
}

Communicator interface is used to handle the service/driver that rubik's inherent communication depends upon

type Controller

type Controller func(*Request)

Controller ...

func Proxy

func Proxy(url string) Controller

Proxy does not redirect your current resource locator but makes an internal GET call to the specified URL to serve it's response as your own

func Render

func Render(btype ByteType, vars interface{}, paths ...string) Controller

Render returns a mixin holding the data to be rendered on the web page or sent over the wire

func UseHandler

func UseHandler(handler http.Handler) Controller

UseHandler converts any http,Handler into rubik.Controller

func UseHandlerFunc

func UseHandlerFunc(fn http.HandlerFunc) Controller

UseHandlerFunc converts any http,HandlerFunc into rubik.Controller

func UseIntermHandler

func UseIntermHandler(intermHandler func(http.Handler) http.Handler) Controller

UseIntermHandler converts any func(http,Handler) http,Handler into rubik.Controller

type DownloadRequestEntity

type DownloadRequestEntity struct {
	Entity
	TargetFilePath string
}

DownloadRequestEntity ...

type Entity

type Entity struct {
	PointTo string
	Params  []string

	FormData   bool
	URLEncoded bool
	JSON       bool
	Infer      interface{}
	Cookies    Values
	// contains filtered or unexported fields
}

Entity holds the data for a single API call It lets you write consolidated clean Go code

type File

type File struct {
	Path   string
	OSFile *os.File
	Raw    []byte
}

File used by ink to embbed file

type FileStore

type FileStore struct {
	Name string
	// contains filtered or unexported fields
}

FileStore lets you perform CRUD on files of StorageContainer FileStore returns the name of container you are accessing by Name field

func (FileStore) Delete

func (fs FileStore) Delete(file string) error

Delete a file from the FileStore, returns error

func (FileStore) Get

func (fs FileStore) Get(file string) []byte

Get a file from this FileStore, returs byte slice

func (FileStore) GetFile

func (fs FileStore) GetFile(file string) *os.File

GetFile returns pointer to os.File for passing it into the rubikClient using File{}.OSFile = return value of this function Other usage may be to obtain file metadata stored

func (FileStore) Has

func (fs FileStore) Has(file string) bool

Has checks if the file by given name is present inside this FileStore

func (FileStore) Put

func (fs FileStore) Put(file string, content []byte) error

Put a file inside this FileStore given the content as parameter

type HookContext

type HookContext struct {
	Request  *http.Request
	Ctx      map[string]interface{}
	Response []byte
	Status   int
}

HookContext ...

type Message

type Message struct {
	Communicator string
	Topic        string
	Body         interface{}
}

Message that is to be sent in communicator channel

type MessagePasser

type MessagePasser struct {
	Message chan Message
	Error   chan error
}

MessagePasser holds the channels for communication with rubik server

type Payload

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

Payload holds the data between the intermediate state of Client and PostProcessor

func (*Payload) Cancel

func (r *Payload) Cancel()

Cancel ...

type RResponseWriter

type RResponseWriter struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

RResponseWriter is Rubik's response writer that implements http.ResponseWriter and it's methods to provide additional functionalities related to Rubik.

func (*RResponseWriter) Write

func (w *RResponseWriter) Write(b []byte) (int, error)

Write writes the response bytes b to the wire

func (*RResponseWriter) WriteHeader

func (w *RResponseWriter) WriteHeader(status int)

WriteHeader writes the http.Request's Header values to the wire and sets the status given as the parameter

type RenderMixin

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

RenderMixin is a mixin holding values for rendering a template

func (RenderMixin) Result

func (rm RenderMixin) Result() []byte

Result returns the parsed/executed content of a template as bytes

type Request

type Request struct {
	Entity interface{}
	Writer RResponseWriter
	Params httprouter.Params
	Raw    *http.Request
	Ctx    context.Context
	// contains filtered or unexported fields
}

Request ...

func (Request) Config

func (req Request) Config(accessor string) interface{}

Config returns the configuration of your server for a specific accessor

func (*Request) GetDep added in v0.2.1

func (req *Request) GetDep() interface{}

GetDep returns the global one time dependencies to your handlers

func (Request) GetRouteTree

func (req Request) GetRouteTree() RouteTree

GetRouteTree returns a list of loaded routes in rubik

func (*Request) Redirect

func (req *Request) Redirect(url string, customStatus ...int)

Redirect redirects your request to the given URL with status 302 by default. If you want to provide a custom status for your redirection you can do that by passing in a custom status like so:

func someCtl(req *Request) {
	req.Redirect("https://ashishshekar.com", http.StatusTemporaryRedirect)
}

func (*Request) Respond

func (req *Request) Respond(data interface{}, ofType ...ByteType)

Respond is a terminal function for rubik controller that sends byte response it wraps around your arguments for better reading

func (*Request) Throw

func (req *Request) Throw(status int, err error, btype ...ByteType)

Throw writes an error with given status code as response The ByteType parameter is optional as you can convert your error into a JSON or plain text

NOTE: if you dont have an error object with you in the moment you can use r.E() to quickly wrap your stirng into an error and pass it inside this function

Example
package main

import (
	"github.com/rubikorg/rubik"
)

func main() {
	func(req *rubik.Request) {
		req.Throw(403, rubik.E("invalid token or something"))
	}(&rubik.Request{})
}
Output:

type RequestHook

type RequestHook func(*HookContext)

RequestHook ...

type Response

type Response struct {
	Status     int
	Body       interface{}
	Raw        *http.Response
	ParsedBody interface{}
	StringBody string
	IsJSON     bool
}

Response is a struct that is returned by every client after request is made successful

type RestErrorMixin

type RestErrorMixin struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

RestErrorMixin type is used by rubik when rubik.Throw is called for writing error types as common JSON structure ocross Rubik server

func (RestErrorMixin) Error

func (re RestErrorMixin) Error() string

Error implements the errror interface of Go

type Route

type Route struct {
	Path                 string
	Method               string
	Description          string
	ResponseDeclarations map[int]string
	JSON                 bool
	Entity               interface{}
	Guard                AuthorizationGuard
	Middlewares          []Controller
	Validation           Validation
	Controller           Controller
}

Route defines how a specific route route inside the Rubik server must behave. Route collects all the information required for processing of a HTTP request and performs a handler construction depending upon these values.

There is a specific order in which handlers of Routes are constructed:

[ Entity check --- Guard() --- Validation() --- []Middlewares() --- Controller() ]

type RouteInfo

type RouteInfo struct {
	Path        string
	Description string
	BelongsTo   string
	Entity      interface{}
	IsJSON      bool
	Method      string
	Responses   map[int]string
}

RouteInfo is a flat structure for processing information about the routes

type RouteTree

type RouteTree struct {
	RouterList map[string]string
	Routes     []RouteInfo
}

RouteTree represents your routes as a local map for getting information about your routes

type Router

type Router struct {
	Middleware  []Controller
	Description string
	// contains filtered or unexported fields
}

Router is used to hold all your rubik routes together

func Create

func Create(index string) Router

Create retuens a rubik.Router instance for using and grouping routes. It is generally used if you want to add routes under the same umbrella prefix of this router. In Rubik it is used to group routes by domains/ responsibilities.

func (*Router) Add

func (ro *Router) Add(r Route)

Add injects a rubik.Route definition to the parent router from which it is called

type StorageContainer

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

StorageContainer is abstracted struct to access your storage files. It can access of remove a whole container.

Container corresponds to a single directory in your storage folder and will have access to files only inside this container/directory

func (StorageContainer) Access

func (s StorageContainer) Access(name string) (FileStore, error)

Access a FileStore from your StorageContainer. It can be viewed as accessing a specific folder inside your storage/ folder and performing operations inside of that folder

func (StorageContainer) Remove

func (s StorageContainer) Remove(name string) error

Remove a FileStore from your StorageContainer. Removing a FileStore will remove all the files inside the FileStore

type TestProbe

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

TestProbe is an abstraction for easily testing your rubik routes

func NewProbe

func NewProbe(ro Router) TestProbe

NewProbe returns a probe for testing your rubik server

Example:

var probe rubik.TestProbe
func init() {
	// pass the rubik.Router you want to test
	probe = rubik.NewProbe(index.Router)
}

func TestSomeRoute(t *testing.T) {
	// returns the *http.Request, *httptest.ResponseRecorder used inside the test
	req, rr := probe.Test(en)
	if rr.Result().StatusCode != 200 { /* Something is wrong */}
}

func (TestProbe) Test

func (p TestProbe) Test(method, path string, reqBody io.Reader, en interface{},
	ctl Controller) (*http.Request, *httptest.ResponseRecorder)

Test a route with method, path to request, Entity (if used) and the controller to test

func (TestProbe) TestHandler

func (p TestProbe) TestHandler(method, path string, reqBody io.Reader, en interface{},
	h http.Handler) (*http.Request, *httptest.ResponseRecorder)

TestHandler is a probe util function to test your handler if you are not using a rubik.Controller for your route and using UseHandler() to cast it

type Validation

type Validation map[string]string

Validation is validation operations to be performed on the request entity

type Values

type Values map[string]interface{}

Values that transcends url.Values allowing any type as value

func (Values) Encode

func (val Values) Encode() string

Encode converts the values into urlencoded strings

func (Values) Set

func (val Values) Set(key string, value interface{})

Set assigns a value for key `key` inside the rubik.Values

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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