Skip to content

basically a remarkable framework for building JSON-based web APIs in Golang

License

Notifications You must be signed in to change notification settings

opensauceryafrica/barf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

barf - Basically A Remarkable Framework

BARF is a small and unobtrusive framework for building JSON-based web APIs on REST or GraphQL-based architectures. It is implemented such that getting started is easy and quick, but it is also flexible enough to allow for more complex use cases.

  • No application instance
  • No bullsh*t context
  • ...and no re-inventing the wheel

It’s just what you need being provided to you in an unobtrusive way.

image

Installation

go get github.com/opensaucerer/barf

Usage

For a comprehensive overview on how to use barf, please refer to the example folder and its sub folders.

A simple BARF REST API

package main

import (
	"log"
	"net/http"

	"github.com/opensaucerer/barf"
)

func main() {

	// barf tries to be as unobtrusive as possible, so your route handlers still
	// inherit the standard http.ResponseWriter and *http.Request parameters
	barf.Get("/", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "Hello World",
		})
	})

	// create & start server
	if err := barf.Beck(); err != nil {
		// barf exposes a logger instance
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with custom configuration

package main

import (
	"log"
	"net/http"

	"github.com/opensaucerer/barf"
)

func main() {
	// create server
	if err := barf.Stark(barf.Augment{
		Port:     "5000",
		Logging:  barf.Allow(),  // enable request logging
		Recovery: barf.Allow(), // enable panic recovery so barf returns a 500 error instead of crashing
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	barf.Get("/", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "Hello World",
		})
	})

	// start barf server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with Environment Variables

package main

import (
	"log"
	"net/http"

	"github.com/opensaucerer/barf"
)

func main() {

	type Env struct {
		// Port for the server to listen on
		Port string `barfenv:"key=PORT;required=true"` // barfenv tag allows barf to load environment variables
	}

	env := new(Env) // global environment variable

	// you can use barf to dynamically load environment variables into a struct
	if err := barf.Env(env, "example/.env"); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	// create server
	if err := barf.Stark(barf.Augment{
		Port:     env.Port,
		Logging:  barf.Allow(),
		Recovery: barf.Allow(),
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	barf.Get("/", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "Hello World",
		})
	})

	// start server - create & start server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with request body, variable paths and query parameters

package main

import (
	"log"
	"net/http"

	"github.com/opensaucerer/barf"
)

func main() {

	type Env struct {
		// Port for the server to listen on
		Port string `barfenv:"key=PORT;required=true"`
	}

	env := new(Env) // global environment variable

	// load environment variables
	if err := barf.Env(env, "example/.env"); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	// create server
	if err := barf.Stark(barf.Augment{
		Port:     env.Port,
		Logging:  barf.Allow(),
		Recovery: barf.Allow(),
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	barf.Post("/:username", func(w http.ResponseWriter, r *http.Request) {

		var data struct {
			Name string `json:"name"`
			Age  int    `json:"age"`
		}

		err := barf.Request(r).Body().Format(&data)
		if err != nil {
			barf.Response(w).Status(http.StatusBadRequest).JSON(barf.Res{
				Status:  false,
				Data:    nil,
				Message: "Invalid request body",
			})
			return
		}

		params, _ := barf.Request(r).Params().JSON()
		query, _ := barf.Request(r).Query().JSON()

		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    map[string]interface{}{"params": params, "query": query, "body": data},
			Message: "Hello World",
		})
	})

	// start server - create & start server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with multipart/form-data

package main

import (
	"io"
	"net/http"
	"os"

	"github.com/opensaucerer/barf"
)

func main() {

	type Env struct {
		// Port for the server to listen on
		Port string `barfenv:"key=PORT;required=true"`
	}

	env := new(Env) // global environment variable

	// load environment variables
	if err := barf.Env(env, "example/.env"); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	// create server
	if err := barf.Stark(barf.Augment{
		Port:     env.Port,
		Logging:  barf.Allow(), // enable request logging
		Recovery: barf.Disallow(),
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	// create a subrouter (retroframe)
	s := barf.RetroFrame("/api").RetroFrame("/v1")
	s.Get("/about", func(w http.ResponseWriter, r *http.Request) {

		message := "About"

		// parsing form-data
		body, err := barf.Request(r).Form().Body().JSON()
		if err != nil {
			message = err.Error()
		}

		head := barf.Request(r).Form().File().Get("file")
		file, _ := head.Open()
		defer file.Close()

		// save file
		f, err := os.OpenFile(head.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			message = err.Error()
		}
		defer f.Close()
		io.Copy(f, file)

		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    body,
			Message: message,
		})
	})

	// start server - create & start server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with custom middleware

package main

import (
	"log"
	"net/http"

	"github.com/opensaucerer/barf"
)

func main() {
	// create server
	if err := barf.Stark(barf.Augment{
		Port:     "5000",
		Logging:  barf.Allow(),  // enable request logging
		Recovery: barf.Allow(), // enable panic recovery so barf returns a 500 error instead of crashing
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	// apply global middleware to all routes - middleware is applied in the order it is added and must be added before the call to barf.Beck()
	barf.Hippocampus().Hijack(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Println("before 0")
			h.ServeHTTP(w, r)
			log.Println("after 0")
		})
	})

	// define routes
	barf.Get("/", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "Hello World",
		})
	})

	// apply another global middleware
	barf.Hippocampus().Hijack(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Println("before 1")
			h.ServeHTTP(w, r)
			log.Println("after 1")
		})
	})

	// start barf server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

BARF with subrouters

package main

import (
	"net/http"
	"os"

	"github.com/opensaucerer/barf"
)

func main() {
	// create server
	if err := barf.Stark(barf.Augment{
		Port:     "5000",
		Logging:  barf.Allow(), // enable request logging
		Recovery: barf.Allow(), // enable panic recovery so barf returns a 500 error instead of crashing
	}); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}

	barf.Get("/", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "Hello World",
		})
	})

	// create a subrouter (retroframe)
	s := barf.RetroFrame("/api/v1")
	s.Get("/about", func(w http.ResponseWriter, r *http.Request) {
		barf.Response(w).Status(http.StatusOK).JSON(barf.Res{
			Status:  true,
			Data:    nil,
			Message: "About",
		})
	})

	// start barf server
	if err := barf.Beck(); err != nil {
		barf.Logger().Error(err.Error())
		os.Exit(1)
	}
}

Contributing

Barf is an open source project and we welcome contributions of all kinds to help improve the project. Please read our contributing guide to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes to Barf.

For a starting point on features Barf currently lacks, see the issues page.

License

Barf is MIT licensed.

Contributors

Made with contrib.rocks.