hyper

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2024 License: Apache-2.0 Imports: 22 Imported by: 1

README

Hyper

General HTTP helper library aims to be customizable.

Usage
Non-TLS
package main

import (
	"context"
	"os"

	"github.com/infiniteloopcloud/hyper"
	"github.com/infiniteloopcloud/log"
)

func main() {
	var h = hyper.HTTP{
		PreHooks: []func(ctx context.Context){
			preHookSetLogLevel,
		},
		Log: hyper.Logger{
			Infof:  log.Infof,
			Errorf: log.Errorf,
		},
		Address: os.Getenv("SERVICE_HTTP_ADDRESS"),
		Handler: chi.NewRouter(),
	}
	
	h.Run()
}

func preHookSetLogLevel(_ context.Context) {
	log.SetLevel(func() uint8 {
		return 1
	}())
}
TLS
package main

import (
	"context"
	"os"

	"github.com/infiniteloopcloud/hyper"
	"github.com/infiniteloopcloud/log"
)

func main() {
	var h = hyper.HTTP{
		PreHooks: []func(ctx context.Context){
			preHookSetLogLevel,
		},
		Log: hyper.Logger{
			Infof:  log.Infof,
			Errorf: log.Errorf,
		},
		Address: os.Getenv("SERVICE_HTTP_ADDRESS"),
		Handler: chi.NewRouter(),
	}

	// NewEnvironmentTLS able to build PEM block based on the provided information
	if os.Getenv("SERVICE_TLS_SUPPORT") == "PEM_BUILDER" {
		h.TLSEnabled = true
		h.TLS = hyper.NewEnvironmentTLS(hyper.EnvironmentTLSOpts{
			TLSCert:          "SERVICE_TLS_CERT",
			TLSCertBlockType: "SERVICE_TLS_CERT_BLOCK_NAME",
			TLSKey:           "SERVICE_TLS_KEY",
			TLSKeyBlockType:  "SERVICE_TLS_KEY_BLOCK_NAME",
		})
    // NewFileTLS reads the files from the provided location
	} else if os.Getenv("SERVICE_TLS_SUPPORT") == "FILE" {
		h.TLSEnabled = true
		h.TLS = hyper.NewFileTLS(hyper.FileTLSOpts{
			TLSCertPath: "SERVICE_TLS_CERT",
			TLSKeyPath:  "SERVICE_TLS_KEY",
		})
	}
	
	h.Run()
}

func preHookSetLogLevel(_ context.Context) {
	log.SetLevel(func() uint8 {
		return 1
	}())
}
Bind request body
package main

import (
	"net/http"

	"github.com/infiniteloopcloud/hyper"
)

type Request struct {
	Field1 string `json:"field1"`
}

func main() {}

func handler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var reqStruct Request
	// Bind the JSON request
	if err := hyper.Bind(ctx, r, &reqStruct); err != nil {
		hyper.ReturnBadRequest(ctx, w, "invalid request body", err)
		return
	}

	w.WriteHeader(http.StatusOK)
}
Error handling

There are pure error wrappers which wraps the error into a weird.Error:

  • BadRequest(...)
  • NotFound(...)
  • Unauthorized(...)
  • Forbidden(...)
  • InternalServerError(...)

All of these has a Return{...} function if the function has access to http.ResponseWriter

  • ReturnBadRequest(...)
  • ReturnNotFound(...)
  • ReturnUnauthorized(...)
  • ReturnForbidden(...)
  • ReturnInternalServerError(...)
package main

import (
	"net/http"

	"github.com/infiniteloopcloud/hyper"
)

type Request struct {
	Field1 string `json:"field1"`
}

func main() {}

func handler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	var reqStruct Request
	if err := hyper.Bind(ctx, r, &reqStruct); err != nil {
		// Return bad request will write the response into w
		hyper.ReturnBadRequest(ctx, w, "invalid request body", err)
		return
	}

	w.WriteHeader(http.StatusOK)
}
Client

HTTP client-side helper functions.

package main

import (
	"context"

	"github.com/infiniteloopcloud/hyper"
)

type Response struct {
	Field1 string `json:"f"`
}

func main() {
	ctx := context.Background()
	var resp Response
	hyper.Request(ctx, &resp, hyper.RequestOpts{
		Method:         "POST",
		Endpoint:       "/api/endpoint",
		// RequestStruct:  req,
		Client:         hyper.Client(),
	})
	// handle err
	// use resp
}

Documentation

Index

Constants

View Source
const (
	StatusAsLibrary = "lib"
	StatusAsService = "svc"
)
View Source
const HeaderPrefix = "Ctx_"

Variables

View Source
var (
	ErrBindMissingBody = errors.New("request bind error, missing request body")
	ErrBind            = "request bind error, "
)
View Source
var (
	MissingRequestBody = "Missing request body"
	InvalidRequest     = "Invalid request"
)
View Source
var ErrMissingHandler = errors.New("missing http.Handler, pass it in the HTTP struct")

Functions

func BadRequest

func BadRequest(ctx context.Context, msg string, err error) error

func Bind

func Bind(ctx context.Context, r *http.Request, v interface{}) error

Bind is binding the request body into v variable

func Client

func Client() *http.Client

func Created

func Created(ctx context.Context, w http.ResponseWriter, val interface{})

Created build a success response with HTTP Status Created

func ElementIntoHeader

func ElementIntoHeader(ctx context.Context, header http.Header, key log.ContextField) http.Header

func Error

func Error(ctx context.Context, w http.ResponseWriter, err error)

Error build an error response, the HTTP status will get from the error, default 500

func Forbidden

func Forbidden(ctx context.Context, err error) error

func FromHeader

func FromHeader(ctx context.Context, header http.Header, contextKeys map[string]log.ContextField) context.Context

func Generic

func Generic(ctx context.Context, w http.ResponseWriter, val interface{}, statusCode int)

Generic build a generic response

func GetCorrelationID

func GetCorrelationID(ctx context.Context) string

func GetQueryStringParam

func GetQueryStringParam(query url.Values, param string) null.String

GetQueryStringParam getting a query param if exist or return with null.String{Valid: false}

func GetQueryTimeParam added in v0.3.0

func GetQueryTimeParam(query url.Values, param, format string) null.Time

GetQueryTimeParam getting a query param if exist or return with null.Time{Valid: false}

func GetQueryUint64Param

func GetQueryUint64Param(query url.Values, param string) null.Uint64

GetQueryUint64Param getting a query param if exist or return with null.Uint64{Valid: false}

func GetValues

func GetValues(ctx context.Context, contextKeys map[string]log.ContextField) map[interface{}]interface{}

func Hello

func Hello(w http.ResponseWriter, r *http.Request)

Hello returns http.StatusOk and the Hello response

func InternalServerError

func InternalServerError(ctx context.Context, err error) error

func IntoHeader

func IntoHeader(ctx context.Context, header http.Header, contextKeys map[string]log.ContextField) http.Header

func Livez

func Livez(w http.ResponseWriter, r *http.Request)

Livez returns http.StatusOk when the service does not need to be killed

func NoContent

func NoContent(ctx context.Context, w http.ResponseWriter)

NoContent build a no content success response

func NotFound

func NotFound(ctx context.Context, msg string, err error) error

func NotReady

func NotReady()

NotReady disables the server to accept connections

func Ready

func Ready()

Ready enables the server to accept connections

func Readyz

func Readyz(w http.ResponseWriter, r *http.Request)

Readyz returns http.StatusOk when the service is ready accept connections, otherwise Http.StatusServiceUnavailable

func ReadyzWithChecks added in v0.3.4

func ReadyzWithChecks(checks ...func(ctx context.Context) error) func(w http.ResponseWriter, r *http.Request)

func Request

func Request(ctx context.Context, respStruct interface{}, opts RequestOpts) (*http.Response, error)

func ReturnBadRequest

func ReturnBadRequest(ctx context.Context, w http.ResponseWriter, msg string, err error)

func ReturnForbidden

func ReturnForbidden(ctx context.Context, w http.ResponseWriter, err error)

func ReturnInternalServerError

func ReturnInternalServerError(ctx context.Context, w http.ResponseWriter, err error)

func ReturnNotFound

func ReturnNotFound(ctx context.Context, w http.ResponseWriter, msg string, err error)

func ReturnUnauthorized

func ReturnUnauthorized(ctx context.Context, w http.ResponseWriter, err error)

func ServiceLive added in v0.3.0

func ServiceLive(ctx context.Context, url string) error

func ServiceReady added in v0.3.0

func ServiceReady(ctx context.Context, url string) error

func SetClientMaxConnsPerHost

func SetClientMaxConnsPerHost(v int)

func SetClientMaxIdleConns

func SetClientMaxIdleConns(v int)

func SetClientMaxIdleConnsPerHost

func SetClientMaxIdleConnsPerHost(v int)

func SetClientTimeout

func SetClientTimeout(v time.Duration)

func SetJSONEncoder added in v0.4.0

func SetJSONEncoder(e JSONEncoder)

func SilentProxy

func SilentProxy(ctx context.Context, w http.ResponseWriter, resp *http.Response)

func StatusHandler

func StatusHandler(opts StatusOpts) func(w http.ResponseWriter, r *http.Request)

func Success

func Success(ctx context.Context, w http.ResponseWriter, val interface{})

Success build a success response with HTTP Status OK

func SuccessDownload

func SuccessDownload(ctx context.Context, w http.ResponseWriter, res []byte)

SuccessDownload build a success response with content type octet/stream

func Unauthorized

func Unauthorized(ctx context.Context, err error) error

Types

type EnvironmentTLSOpts

type EnvironmentTLSOpts struct {
	TLSCert          string
	TLSCertBlockType string
	TLSKey           string
	TLSKeyBlockType  string
}

type FileTLSOpts

type FileTLSOpts struct {
	TLSCertPath string
	TLSKeyPath  string
}

type HTTP

type HTTP struct {
	TLS        TLSDescriptor
	TLSEnabled bool

	Address string
	Handler http.Handler

	Log Logger

	PreHooks  []func(ctx context.Context)
	PostHooks []func(ctx context.Context)
}

func (HTTP) Run

func (h HTTP) Run()

func (HTTP) Serve

func (h HTTP) Serve(ctx context.Context, finisher chan error)

type JSONEncoder added in v0.4.0

type JSONEncoder interface {
	Decode(r io.Reader, v any) error
	Encode(w io.Writer, v any) error
}

type Logger

type Logger struct {
	Infof  infoLog
	Errorf errorLog
}

type MockReadCloser

type MockReadCloser struct {
	*bytes.Buffer
}

MockReadCloser implements the io.ReadCloser interface Mocks the request.Body

func NewMockReadCloser

func NewMockReadCloser(ctx context.Context, data interface{}) MockReadCloser

func (MockReadCloser) Close

func (cb MockReadCloser) Close() (err error)

type RequestOpts

type RequestOpts struct {
	BaseURL       string
	Method        string
	Endpoint      string
	Request       interface{}
	Headers       map[string]string
	ContextKeys   map[string]log.ContextField
	SkipBodyClose bool

	Client *http.Client
}

type StatusFn

type StatusFn func() string

type StatusOpts

type StatusOpts struct {
	EnvironmentData []string
	Statuses        map[string]StatusFn
}

type TLSDescriptor

type TLSDescriptor interface {
	// contains filtered or unexported methods
}

func NewEnvironmentTLS

func NewEnvironmentTLS(e EnvironmentTLSOpts) TLSDescriptor

func NewFileTLS

func NewFileTLS(e FileTLSOpts) TLSDescriptor

type Wrapper

type Wrapper struct {
	// TokenJWT returns a new JWT token, if it filled that means the frontend should change it
	// NOTE: temporary it's hidden, because we use cookies
	TokenJWT string `json:"-"`

	// UserJWT returns a new JWT with user info, if it filled that means the frontend should change it
	// NOTE: temporary it's hidden, because we use cookies
	UserJWT string `json:"-"`

	// Error
	Error string `json:"error,omitempty"`
	// Data is the exact data of the response
	Data interface{} `json:"data,omitempty"`
}

Wrapper wraps the response

type Writer

type Writer struct {
	W http.ResponseWriter

	StatusCode int
	// contains filtered or unexported fields
}

Writer also implements the http.ResponseWriter interface In the future we may add other fields as well.

func NewWriter

func NewWriter(w http.ResponseWriter) *Writer

NewWriter creates a new Writes

func (*Writer) Header

func (r *Writer) Header() http.Header

Header returns the header map that will be sent by WriteHeader

func (*Writer) ResponseBody

func (r *Writer) ResponseBody() string

func (*Writer) Write

func (r *Writer) Write(bytes []byte) (int, error)

Write writes the data to the connection as part of an HTTP reply, and stores the response data for logging purpose

func (*Writer) WriteHeader

func (r *Writer) WriteHeader(statusCode int)

WriteHeader 'overrides' the http.ResponseWriter's WriteHeader method

Jump to

Keyboard shortcuts

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