microbo

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2020 License: LGPL-3.0 Imports: 17 Imported by: 0

README

Microbo

Microbo is a micro framework to create micro API webservers in go. A webserver that use Microbo require a very minimal configuration (just create a .env file) and support a DB connection, CORS, authentication with JWT and HTTP2 out of the box.

Usage

First of all you have to create .env file like this:

CERT_FILE="./cert/localhost+1.pem"
CERT_KEY="./cert/localhost+1-key.pem"
DB_CONNECTION=":memory:"
JWT_KEY="1234"
ROOT_PATH="/var/www/public"
ROOT_PATH_ENDPOINT="/public/"
SERVER_ADDR="127.0.0.1:3000"

You can generate the certificate using mkcert.

Then create your main.go file

package main

import (
  "encoding/json"
  "fmt"
  "net/http"
  "os"

  "github.com/pioz/microbo"
  "gorm.io/driver/sqlite"
  "gorm.io/gorm"
)

type Server struct {
  *microbo.Server
}

func NewServer(db *gorm.DB) *Server {
  server := &Server{Server: microbo.NewServer(db)}
  server.HandleFunc("GET", "/ping", pingHandler)
  server.HandleFuncWithAuth("GET", "/secure-ping", server.securePingHandler)
  return server
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
  w.Header().Add("Content-Type", "application/json")
  encoder := json.NewEncoder(w)
  encoder.Encode("pong")
}

func (server *Server) securePingHandler(w http.ResponseWriter, r *http.Request) {
  w.Header().Add("Content-Type", "application/json")
  userId := r.Context().Value("user_id").(uint)
  user := microbo.DefaultUser{} // or your user model struct
  server.DB.Where("id = ?", userId).Find(&user)
  encoder := json.NewEncoder(w)
  encoder.Encode(fmt.Sprintf("pong %s", user.Email))
}

func main() {
  os.Setenv("SERVER_ADDR", "127.0.0.1:3001") // override env variable
  db, _ := gorm.Open(sqlite.Open(os.Getenv("DB_CONNECTION")), nil)
  NewServer(db).Run()
}

And yeah, your microservice is ready!

You can use your database with server.DB that is a *gorm.DB pointer. You can find all info about "The fantastic ORM library for Golang" here.

You can use the router with server.Router that is a *mux.Router pointer. You can find all info about "Gorilla web toolkit" here.

Also the following authentication endpoints are available:

  • POST /auth/register
  • POST /auth/login
  • POST /auth/refresh

Here the godoc to know all about microbo.

Questions or problems?

If you have any issues please add an issue on GitHub or fork the project and send a pull request.

Copyright (c) 2020 Enrico Pilotto (@pioz). See LICENSE for details.

Documentation

Overview

Microbo is a micro framework to create micro API webservers in go. A webserver that use Microbo require a very minimal configuration (just create a .env file) and support a DB connection, CORS, authentication with JWT and HTTP2 out of the box.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Conf

type Conf struct {
	// Pointer to gorm ORM database.
	// See https://pkg.go.dev/gorm.io/gorm#DB
	DB *gorm.DB
	// Set a custom user model. The custom user model must implement the interface UserModel. Here and example:
	//  type FullUser struct {
	//   	UID         uint `gorm:"auto_increment;primary_key"`
	//   	Mail        string
	//   	EncPassword string
	//   	Username    string
	//   	Role        bool
	//  }
	//
	//  func (u FullUser) GetID() uint {
	//  	return u.UID
	//  }
	//
	//  func (u FullUser) GetEmail() string {
	//  	return u.Mail
	//  }
	//
	//  func (u FullUser) GetPassword() string {
	//  	return u.EncPassword
	//  }
	//
	//  func (FullUser) TableName() string {
	//  	return "user"
	//  }
	//
	//  func (FullUser) EmailColumnName() string {
	//  	return "mail"
	//  }
	//
	//  func (user *FullUser) ID(id uint) {
	//  	user.UID = id
	//  }
	//
	//  // Used for copier (see https://github.com/jinzhu/copier)
	//  func (user *FullUser) Email(email string) {
	//  	user.Mail = email
	//  }
	//
	//  // Used for copier (see https://github.com/jinzhu/copier)
	//  func (user *FullUser) Password(password string) {
	//  	user.EncPassword = password
	//  }
	//
	//  func (u FullUser) MarshalJSON() ([]byte, error) {
	//  	return json.Marshal(struct {
	//  		ID        uint   `json:"id"`
	//  		Mail      string `json:"mail"`
	//  		Username  string `json:"username"`
	//  		RandToken string `json:"rand_token"`
	//  	}{
	//  		ID:        u.UID,
	//  		Mail:      u.Mail,
	//  		Username:  u.Username,
	//  		RandToken: "RAND TOKEN",
	//  	})
	//  }
	//
	//  conf := microbo.Conf{UserModel: &FullUser{}}
	//  server := microbo.NewServerWithOpts(&conf)
	//  server.Run()
	// The /auth/login endpoint will return the user json defined by
	// FullUser#MarshalJSON.
	UserModel UserModel
	// The Log middleware
	// See https://godoc.org/github.com/gorilla/mux#Router.Use
	LogMiddleware mux.MiddlewareFunc
	// The Timeout middleware. The default use http.TimeoutHandler with dt
	// parameters set to 2 seconds.
	// See https://godoc.org/net/http#TimeoutHandler
	// See https://godoc.org/github.com/gorilla/mux#Router.Use
	// An example to change the timeout:
	//  conf := microbo.Conf{
	//  	TimeoutMiddleware: func(next http.Handler) http.Handler {
	//  		return http.TimeoutHandler(next, 60*time.Second, "Timeout")
	//  	},
	//  }
	TimeoutMiddleware mux.MiddlewareFunc
	// ReadTimeout is the maximum duration for reading the entire request,
	// including the body.
	// See https://godoc.org/net/http#Server
	ReadTimeout *time.Duration
	// WriteTimeout is the maximum duration before timing out writes of the
	// response.
	// See https://godoc.org/net/http#Server
	WriteTimeout *time.Duration
}

type DefaultUser

type DefaultUser struct {
	ID       uint   `json:"id"`
	Email    string `json:"email"`
	Password string `json:"-"`
}

The default user struct used to manage users. However, you can always use your own user model (see below).

func (DefaultUser) EmailColumnName

func (DefaultUser) EmailColumnName() string

Return the user email column name in your DB. Default "email".

func (DefaultUser) GetEmail

func (u DefaultUser) GetEmail() string

Return the email of user record as string.

func (DefaultUser) GetID

func (u DefaultUser) GetID() uint

Return the ID of user record as uint.

func (DefaultUser) GetPassword

func (u DefaultUser) GetPassword() string

Return the encrypted password of user record as string.

func (DefaultUser) TableName

func (DefaultUser) TableName() string

Return the user table name in your DB. Default "users".

type Server

type Server struct {
	// http.Server variable. See https://godoc.org/net/http#Server
	http.Server
	// Router registers routes to be matched and dispatches a handler. See
	// https://godoc.org/github.com/gorilla/mux#Router
	Router *mux.Router
	// Pointer to gorm ORM database. See
	// https://pkg.go.dev/gorm.io/gorm#DB
	DB *gorm.DB
	// The path of the public folder. Files inside will be serverd as static
	// files.
	RootPath string
	// contains filtered or unexported fields
}

The base server struct. It contains the Router and the DB access.

func NewServer

func NewServer(db *gorm.DB) *Server

Create a new Microbo server.

Microbo uses config enviroment variables that can be store in a handy .env file. The available env variables are:

  • CERT_FILE: path to the certificate file (.pem). For dev purpose you can use mkcert (https://github.com/FiloSottile/mkcert).
  • CERT_KEY: path to the certificate key file (.pem).
  • DB_CONNECTION: a Gorm database connection string (es: "root@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True").
  • ROOT_PATH: path of the public root path. Files inside will be served as static files.
  • ROOT_PATH_ENDPOINT: URL path to access public files (es: /public/).
  • SERVER_ADDR: the server address with port (es: 127.0.0.1:3000).
  • JWT_KEY: the JWT key used to sign tokens.

func NewServerWithOpts

func NewServerWithOpts(conf *Conf) *Server

Create a new Microbo server with configuration options.

func (*Server) HandleFunc

func (server *Server) HandleFunc(method, path string, f func(http.ResponseWriter, *http.Request))

HandleFunc registers the handler function for the given pattern in the mux Router. The documentation for ServeMux explains how patterns are matched. See https://godoc.org/net/http#HandleFunc

func (*Server) HandleFuncWithAuth

func (server *Server) HandleFuncWithAuth(method, path string, f func(http.ResponseWriter, *http.Request))

Handles registered with HandleFuncWithAuth must be requested with a valid JWT bearer token. Inside the handler you can retrieve the authenticated userId with

userId := r.Context().Value("user_id").(uint)

Built in authentication endpoints are:

// Register a new user
curl --location --request POST 'https://localhost:3000/auth/register' \
--header 'Content-Type: application/json' \
--data-raw '{
  "email": "epilotto@gmx.com",
  "password": "qwerty"
}'

Return 200 if user has successfully registered, or other http error codes if not. No body will be returned in the response.

// Get a new JWT token
curl --location --request POST 'https://localhost:3000/auth/login' \
--header 'Content-Type: application/json' \
--data-raw '{
  "email": "epilotto@gmx.com",
  "password": "qwerty"
}'

Return 200 and the json with user data if user has successfully autheticated. The token will be present in the header under the X-Token key.

// Refresh a JWT token
curl --location --request POST 'https://localhost:3000/auth/refresh' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjExLCJleHAiOjE1ODc2NzIzOTl9.vEoYBueacCA_JQkPmDCwpfIutsC5jQmYfL692q0Nrrk' \
--header 'Content-Type: application/json'

Return 200 if the token has successfully refreshed. The new token will be present in the header under the X-Token key. No body will be returned in the response.

Also, these endpoints and the authentication with JWT token are enabled only if exists the env variable JWT_KEY and a database table named "users" with the columns "id", "email" and "password". Password will be stored as a bcrypt hash.

func (*Server) Run

func (server *Server) Run()

Run the server.

func (*Server) Shutdown

func (server *Server) Shutdown()

Shutdown the server.

type UserModel

type UserModel interface {
	GetID() uint
	GetEmail() string
	GetPassword() string
	TableName() string
	EmailColumnName() string
}

This is the interface that you have to implement to use a custom user model.

Jump to

Keyboard shortcuts

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