• Stars
    star
    182
  • Rank 211,154 (Top 5 %)
  • Language
    Go
  • License
    BSD 3-Clause "New...
  • Created over 2 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Jett is a lightweight micro-framework for building Go HTTP services. Built on top of HttpRouter, enables subrouting and flexible addition of middleware at any level ๐Ÿš€

GitHub go.mod Go version GitHub release (latest by date including pre-releases) GitHub Repo stars

Jett is a lightweight micro-framework for building Go HTTP services. It builds a layer on top of HttpRouter to enable subrouting and flexible addition of middleware at any level - root, subrouter, a specific route.

Jett strives to be simple and easy to use with minimal abstractions. The core framework is less than 300 loc but is designed to be extendable with middleware. Comes packaged with a development server equipped for graceful shutdown and a few essential middleware.

Key Features :

  • Build REST APIs quickly with minimal abstraction!

  • Add middleware at any level - Root, Subrouter or in a specific route!

  • Built-in development server with support for graceful shutdown and shutdown functions.

  • Highly flexible & easily customisable with middleware.

  • Helpful response renderers for HTML, JSON, XML and Plain Text.

  • Clean and simple code. Jett's core is less than 300 LOC.

  • Extremely lightweight. Built on top of net/http & HttpRouter.

package main

import (
	"fmt"
	"net/http"
	"github.com/saurabh0719/jett"
	"github.com/saurabh0719/jett/middleware"
)

func main() {

	r := jett.New()

	r.Use(middleware.RequestID, middleware.Logger)

	r.GET("/", Home)
	
	r.Run(":8000")
}

func Home(w http.ResponseWriter, req *http.Request) {
	jett.JSON(w, "Hello World", 200)
}

Install -

$ go get github.com/saurabh0719/jett

Table of Contents :


Using Middleware

Jett supports any Middleware of the type func(http.Handler) http.Handler.

Some essential middleware are provided out of the box in github.com/saurabh0719/jett/middleware -

  • RequestID : Injects a request ID into the context of each request

  • Logger : Log request paths, methods, status code as well as execution duration

  • BasicAuth : Basic Auth middleware, RFC 2617, Section 2

  • Recoverer : Recover and handle panic

  • NoCache : Sets a number of HTTP headers to prevent a router (or subrouter) from being cached by an upstream proxy and/or client

  • HeartBeat : Set up an endpoint to conveniently ping your server.

  • Timeout : Timeout is a middleware that cancels context after a given timeout

func (r *Router) Use(middleware ...func(http.Handler) http.Handler)

Middleware can be added at the at a Router level (root, subrouter) ...

package main

import (
	"fmt"
	"net/http"
	"github.com/saurabh0719/jett"
	"github.com/saurabh0719/jett/middleware"
)

func main() {

	r := jett.New()

	r.Use(middleware.RequestID, middleware.Logger)

	r.GET("/", Home)
	
	r.Run(":8000")
}

OR on each individual route

func (r *Router) GET(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

To access a router's middleware stack -

// Middleware returns a slice of the middleware stack for the router
func (r *Router) Middleware() []func(http.Handler) http.Handler

Example -

func main() {

	r := jett.New()

	r.GET("/", Home, middleware.Logger, middleware.Recover)
	
	r.Run(":8000")
}

Go back to the table of contents


Subrouter

The Subrouter function returns a new Router instance.

Example -

package main

import (
	"fmt"
	"net/http"
	"github.com/saurabh0719/jett"
	"github.com/saurabh0719/jett/middleware"
)
func main() {

	r := jett.New()

	r.Use(middleware.RequestID)

	r.GET("/", Home)

	sr := r.Subrouter("/about")
	sr.Use(middleware.Logger)
	sr.GET("/", About, middleware.NoCache)

	r.Run(":8000")
}

func Home(w http.ResponseWriter, req *http.Request) {
	jett.JSON(w, "Hello World", 200)
}

func About(w http.ResponseWriter, req *http.Request) {
	jett.TEXT(w, "About", 200)
}

Register routes

// These functions optionally accept their own unique middleware for their handlers

func (r *Router) GET(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) HEAD(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) OPTIONS(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) POST(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) PUT(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) PATCH(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

func (r *Router) DELETE(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

// Any() creates routes for the methods mentioned above ^ - it DOES NOT actually match any random arbitrary method method
func (r *Router) Any(path string, handlerFn http.HandlerFunc, middleware ...func(http.Handler) http.Handler)

You can also directly call the Handle function that accepts an http.Handler

func (r *Router) Handle(method, path string, handler http.Handler, middleware ...func(http.Handler) http.Handler)

Go back to the table of contents


Serving static files

The ServeFiles is a wrapper around httprouter.ServeFiles to serve statice assets.

func (r *Router) ServeFiles(path string, root http.FileSystem)

From HttpRouter router.go

ServeFiles serves files from the given file system root. The path must end with "/*filepath", files are then served from the local path /defined/root/dir/*filepath.

For example if root is "/etc" and *filepath is "passwd", the local file "/etc/passwd" would be served. Internally a http.FileServer is used, therefore http.NotFound is used instead of the Router's NotFound handler.

To use the operating system's file system implementation, use http.Dir: router.ServeFiles("/src/*filepath", http.Dir("/var/www"))

Eg. r.ServeFiles("/static/*filepath", http.Dir("static"))

See a full example here


Path & Query parameters

Path parameters -

// Helper function to extract path params from request Context()
// as a map[string]string for easy access
func URLParams(req *http.Request) map[string]string

Query parameters -

// Helper function to extract query params as a map[string][]string
// Eg. /?one=true,false&two=true
// {"two" : ["true"], "one": ["true, "false"]}
func QueryParams(req *http.Request) map[string][]string

Example -

func main() {

	r := jett.New()

	r.GET("/person/:id", Person)

	r.Run(":8000")
}

func Person(w http.ResponseWriter, req *http.Request) {
	params := jett.URLParams(req)
	
    // do something and prepare resp

	jett.JSON(w, resp, http.StatusOK)
}

Go back to the table of contents


Development Server

Jett comes with a built-in development server that handles graceful shutdown. You can optionally specify multiple cleanup functions to be called on shutdown.

Run without context -

func (r *Router) Run(address string, onShutdownFns ...func())
func (r *Router) RunTLS(address, certFile, keyFile string, onShutdownFns ...func())

Run with context -

Useful when you need to pass a top-level context. Shutdown process will begin when the parent context cancels.

func (r *Router) RunWithContext(ctx context.Context, address string, onShutdownFns ...func())
func (r *Router) RunTLSWithContext(ctx context.Context, address, certFile, keyFile string, onShutdownFns ...func())

Example -

server.go

package main

import (
	"context"
	"fmt"
	"github.com/saurabh0719/jett"
	"net/http"
	"time"
)

func main() {

	r := jett.New()

	r.GET("/", Home)

	// automatically trigger shutdown after 10s
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	r.RunWithContext(ctx, ":8000", shutdownOne, shutdownTwo)
}

func Home(w http.ResponseWriter, req *http.Request) {
	jett.TEXT(w, "Hello World!", 200)
}

// Shutdown functions called during graceful shutdown
func shutdownOne() {
	time.Sleep(1 * time.Second)
	fmt.Println("shutdown function 1 complete!")
}

func shutdownTwo() {
	time.Sleep(1 * time.Second)
	fmt.Println("shutdown function 2 complete!")
}
$ go run server.go

Please note that this Server is for development only. A production server should ideally specify timeouts inside http.Server. Any contributions to build upon this is welcome.

Go back to the table of contents


Response renderers

Optional helpers for formatting the output. Content type is set automatically.

// JSON output - Content-Type - application/json
func JSON(w http.ResponseWriter, data interface{}, status int)

// Plain Text output - Content-Type - text/plain
func Text(w http.ResponseWriter, data string, status int)

// XML output - Content-Type - application/xml
func XML(w http.ResponseWriter, data interface{}, status int)

For html templates (status is set internally, default 200 OK else Server error)

// Content-Type - text/html
func HTML(w http.ResponseWriter, data interface{}, htmlFiles ...string) 

data can be nil or any struct that the template needs. You can also send multiple templates in order of parent -> child

jett.HTML(w, nil, "layout.html", "index.html")

A simple example -

Directory Structure -

example/
	- static/
		- styles.css
	- index.html
	- server.go
  • index.html
- <html>
- <head>
- 	<link rel="stylesheet" href="/static/styles.css">
- </head>
- 
- <body>
- 	<h1>This is a heading</h1>
- </body>
- </html>
  • styles.css
- body {
-     background-color: #FFD500;
- }
  • server.go
package main

import (
	"fmt"
	"net/http"
	"github.com/saurabh0719/jett"
	"github.com/saurabh0719/jett/middleware"
)

func main() {

	r := jett.New()

	r.Use(middleware.RequestID, middleware.Logger)

	r.ServeFiles("/static/*filepath", http.Dir("static"))

	r.GET("/:name", Home)

	r.Run(":8000")
}

func Home(w http.ResponseWriter, req *http.Request) {
	params := jett.URLParams(req)
	p := Person{
		name: params["name"]
	}
	jett.HTML(w, p, "index.html")
}

Contribute

Author and maintainer - Saurabh Pujari

Logo design - Akhil Anil

Actively looking for Contributors to further improve upon this project. If you have any interesting ideas or feature suggestions, don't hesitate to open an issue!

Go back to the table of contents


More Repositories

1

elara

Elara DB is an easy to use, lightweight persistent key-value store that can also be used as a fast in-memory cache. Manipulate data structures in-memory, encrypt database files and export data. ๐ŸŽฏ
Python
118
star
2

constable

Constable lets you be lazy by inserting prints directly into your AST for stateful debugging ๐Ÿคนโ€โ™‚๏ธ
Python
93
star
3

go-hashlru

A simple thread-safe and fixed size LRU. Based on the Hashlru Algorithm ๐Ÿ”ƒ
Go
72
star
4

object-tracker

A pure python Object state change tracker. Monitor all changes in the object's lifecycle and trigger callback functions. ๐Ÿ“
Python
22
star
5

py-rules-engine

A pure-python rules engine. Packed with components to build rules and a rule parser. โ–ถ๏ธ
Python
14
star
6

automate-mediaconvert

Automate video transcoding and generate thumbnails with AWS Elemental Mediaconvert and S3 โšก
Python
8
star
7

pswHash

Go implementation of Django's default password hasher. Uses the pbkdf2 algorithm along with a sha256 digest. ๐Ÿ”
Go
7
star
8

Optical-flow-calculation

Object tracking using Lucas-Kanade algorithm
C++
4
star
9

Personal-Finances-Calculator

Calculates common finance values, GUI design pending
Java
3
star
10

ez-ToDo

A clean To-do list desktop application written in electron ๐Ÿ“š
JavaScript
2
star
11

saurabh0719

2
star
12

python-random-quote

A file-based quote bot written in Python
Python
2
star
13

Ageing-priority-queue

A priority queue that uses ageing to prevent process starvation.
C
2
star
14

Encrypted-Client-Server-chat

Key encrypted client-server chat service
Java
1
star
15

Django-REST-APIs

Python
1
star
16

dmdw-clustering

Python
1
star
17

covidy

Get live coronavirus statistics of any country or continent into your terminal window ๐Ÿ“ข
JavaScript
1
star
18

simulate-revenue

Run simulations and compare results between Pro Rata and User Centric revenue models used by streaming platforms โœ”๏ธ
Python
1
star
19

video-processing

Video processing exercises in C using FFmpeg library ๐Ÿ“
C
1
star
20

fs-estimate

Estimate reading time for any text file
JavaScript
1
star
21

deploy.sh

Bash utility to deploy serverless python applications to AWS Lambda with Zappa โšก
Shell
1
star
22

dspd-lab-qns

solutions to the dspd lab questions
C
1
star
23

Bifid-cipher

C++
1
star
24

gitmeup

cli tool to automate repetitive git commands. ๐Ÿ’ป
JavaScript
1
star
25

AngularJS-CRUD-studentDB

Front-end static student DB using AngularJS. Backend pending
HTML
1
star
26

java-Assistant

performs simple tasks lol
Java
1
star
27

js-validation

A login verification template done using Regular Expressions in Javascript.
HTML
1
star
28

mysql-server-terminal

Java
1
star