respond

package module
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: May 14, 2021 License: MIT Imports: 9 Imported by: 10

README

Respond

Go Report Card

This package reduces the verbosity associated with responding to HTTP requests when using standard net/http handlers (with a bent towards JSON based REST APIs). Most HTTP handling examples using the standard library tend to be 25% handling logic and 75% dealing with data marshaling, header management, status code updates, etc. Respond tries to flip that ratio so more of your code is business logic while still giving you robust, readable, maintainable response handling.

You focus on writing awesome code that does something meaningful and respond takes care of the messy code that figures out how to send your result to the caller.

Getting Started
go get -u github.com/monadicstack/respond
Basic Example

Here is a sample HTTP handler using the standard library.

func MyHandler(w http.ResponseWriter, req *http.Request) {
    userID := param(req, "user")
    user, err := userRepo.FindById(userID)

    if err != nil {
	    http.Error(w, err.Error(), 500)
	    return
    }
    jsonBytes, err := json.Marshal(user)
    if err != nil {
    	http.Error(w, err.Error(), 500)
    	return
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(200)
    w.Write(jsonBytes)
}

Here is the same handler using the respond package. Create a Responder for your writer/request pair and use the aptly-named functions that line up to the type of HTTP response you want.

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    userID := param(req, "user")
    user, err := userRepo.FindById(userID)

    // If you want a 200 status...
    response.Ok(user, err)
}
Success Responses

Responders have named helpers for some of the more common success codes you might want to respond with:

response := respond.To(w, req)
...

// Responds w/ a 200 and 'someValue' as JSON 
response.Ok(someValue)

// Responds w/ a 201 and 'someValue' as JSON 
response.Created(someValue)

// Responds w/ a 202 and 'someValue' as JSON 
response.Accept(someValue)

// Responds w/ a 204 and no body. 
response.NoContent()

// Responds w/ a 304 and no body. 
response.NotModified()
Error Handling

The Responder type has a bunch of helpful functions for responding with meaningful error statuses and messages. All error messages support printf style formatting.

response := respond.To(w, req)
...
// Status => 401
// Body   => { "status": 401, "message": "what, no credentials?" }
response.Unauthorized("what, no credentials?")

// Status => 403
// Body   => { "status": 403, "message": "missing 'badass' role" }
response.Forbidden("missing '%s' role", someRole)

// Status => 404
// Body   => { "status": 404, "message": "unable to find user [123]" }
response.NotFound("unable to find user [%s]", userID)

// Status => 500
// Body   => { "status": 500, "message": "what did you do!?!" }
response.InternalServerError("what did you do!?!")

// Status => 503
// Body   => { "status": 503, "message": "not working right now" }
response.ServiceUnavailable("not working right now")

These are just a few common ones. Check the docs or use auto-complete in your IDE to see which errors are supported.

Here's a common pattern for utilizing these response functions if you use named errors. It gives you strongly coded errors while left-aligning your code to help keep your handler code more idiomatic. If you have more control over the errors you generate, take a look at the next section to see how you can reduce this boilerplate even further.

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    userID := param(req, "user")
    user, err := userRepo.FindById(userID)

    switch err {
    case ErrNoSuchAccount:
        response.NotFound("no such users: %s", userID)
    case ErrDatabaseConn:
        response.ServiceUnavailable("user database unavailable")
    default:
        response.Ok(user, err)
    }
}
Error Handling: Shorthand

While it has its places, writing those switch statements to respond with the correct status code can be a pain. All of the success response functions like Ok(), Accepted(), etc accept an optional Error argument (yes... by bastardizing variadic functions... sorry).

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    userID := param(req, "user")
    user, err := userRepo.FindById(userID)

    // When 'err' is nil, the result will be a 200 w/ the user
    // data as JSON. When 'err' is non-nil, we'll ignore the
    // user data and return a 4XX/5XX error w/ err's message.
    response.Ok(user, err)
}
How Does It Know Which 4XX/5XX Status To Use?

respond uses Go 1.13 error unwrapping to detect if your error conforms to one of these three error interfaces:

  • ErrorWithCode
  • ErrorWithStatus
  • ErrorWithStatusCode

These are all Error interfaces that also contain either of these functions:

  • func Code() int
  • func Status() int
  • func StatusCode() int

This allows you to use your own custom error types, and as long as they have one of these 3 functions, respond will use that status code in the error.

Here is a sample error you might write that satisfies the ErrorWithCode interface.

type NotFoundError struct {
    message string
}
func (err NotFoundError) Error() string {
    return err.message
}
func (err NotFoundError) Code() int {
    return 404
}

Your business logic can just naturally return meaningful errors.

func (repo *UserRepo) FindById(userID string) (*User, error) {
    user := User{}
    row := repo.db.Query("...")
    err := row.Scan(...)

    switch err {
    case sql.ErrNoRows:
        return nil, NotFoundError{message: "no such user"} 
    default:
        return user, err
}

Now your handler will return a 404 when the user doesn't exist and fall back to a good 'ol 500 on any other type of error. Like before, if there was no error, this will result in a 200 w/ the user data.

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    userID := param(req, "user")
    user, err := userRepo.FindById(userID)

    response.Ok(user, err)
}
Redirects

Depending on what will make your handler more clear, you have two options for triggering an HTTP redirect response:

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    fileID := param(req, "file")
    file, ok := fileStore.GetFileInfo(fileID)
    if !ok {
        response.NotFound("file not found: %s", fileID)
        return
    }

    response.Redirect("https://%s.s3.amazonaws.com/%s/%s",
    	file.Bucket,
    	file.Directory,
    	file.Name,
    )
}

This is fine when your redirects are simple, but the more complex your substitutions are, the more you lose clarity because your focus is drawn to the URL substitution rather than the actual business logic.

Alternately, you can use RedirectTo() and pass any value that implements the Redirector interface; basically can return the fully-formed URL that you want to redirect to. This can help clean up your handlers by moving the URL building logic elsewhere, so your handler stays lean and mean:

func MyHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    fileID := param(req, "file")
    file, ok := fileStore.GetFileInfo(fileID)
    if !ok {
        response.NotFound("file not found: %s", fileID)
        return
    }
    response.RedirectTo(file)
}
type S3FileInfo struct {
    Bucket    string
    Directory string
    Name      string
}

func (f S3FileInfo) Redirect() string {
    return fmt.Sprintf("https://%s.s3.amazonaws.com/%s/%s", 
        file.Bucket,
        file.Directory,
        file.Name,
    )
}

As you can see, your handler is a bit cleaner, and it's easier to reason about what it's actually doing. Additionally, you can write URL formatting tests independent of your handler tests.

One final note. Both Redirect() and RedirectTo() have "permanent" variants that result in a 308 HTTP status rather than a 307: RedirectPermanent() and RedirectPermanentTo().

Responding With Images And Other Raw Files

You can use the Serve() and Download() functions to deliver raw file data rather than marshaled JSON. Both accept an io.Reader as the data source.

func ProfilePictureHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    userID := param(req, "user")
    image, err := pictureStore.ReadFile(userID + ".jpg")
    defer imageReader.Close()

    // Deliver the picture "inline" for use in an <img> tag.
    response.Serve("profile.jpg", image, err)

    // OR

    // Offer a download dialog for the image
    response.Download("profile.jpg", image, err)
}

In addition to writing the bytes, respond will apply the correct Content-Type and Content-Disposition headers based on the name/extension of the file you provide.

Raw Files By Implementing ContentReader

If you'd like to decouple yourself further from the respond library when serving up raw files, you can continue to respond using Ok() with your own structs/values as long as it implements ContentReader - which basically means that it has a Content() method that returns an io.Reader with the raw data.

Instead of marshaling the result value as JSON and responding with those bytes, it will respond with the raw bytes your reader supplies.

func ExportCSV(w http.ResponseWriter, req *http.Request) {
    // This is an *Export which implements ContentReader
    export := crunchTheNumbers() 

    // Respond with the raw CSV reader data and the following:
    // Status = 200
    // Content-Type = 'application/octet-stream'
    // Content-Disposition = 'inline'
    // Body = (whatever .Read() gave us)
    respond.To(w, req).Ok(export)
}

type Export struct {
    csvData *bytes.Buffer
}

func (e Export) Content() io.Reader {
    return e.csvData
}

Most of the time, however, you probably don't want that generic content type. Additionally, there may be instances where you'd rather have the client trigger a download rather than consume the content inline.

To rectify that, you can implement two optional interfaces to customize both behaviors:

// Implement this to customize the "Content-Type" header.
type ContentTypeReader interface {
    ContentType() string
}

// Implement this to allow an "attachment" disposition instead.
// The value you return will be the default file name offered to
// the client/user when downloading.
type ContentFileNameReader interface {
    ContentFileName() string
}

Updating our example to customize both values, we end up with the following:

func ExportCSV(w http.ResponseWriter, req *http.Request) {
    // This is an *Export which implements all 3 Content-based interfaces
    export := crunchTheNumbers()

    // Respond with the raw CSV reader data and the following:
    // Status = 200
    // Content-Type = 'text/csv'
    // Content-Disposition = 'attachment; filename="super-important-report.csv"'
    // Body = (whatever .Read() gave us)
    respond.To(w, req).Ok(export)
}

// ---

type Export struct {
    RawData *bytes.Buffer
}

func (e Export) Content() io.Reader {
    return e.csvData
}

func (e Export) ContentType() string {
    return "text/csv" 
}

func (e Export) ContentFileName() string {
    return "super-important-report.csv"
}
Responding With HTML

While most of respond was built to support building REST APIs, you can just as easily respond w/ HTML if your application does server-side rendering. Using the HTML() and HTMLTemplate() functions, you can easily send 200 responses w/ the Content-Type set to text/html; charset=utf-8.

You can respond with a pre-rendered block of HTML.

func LoginHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    // ... do some work ...
    
    html := "<h1>Hello " + username + "</h1>"
    response.HTML(html)
}

Or you can use a standard Go html/template. The Responder will evaluate the template for you, and the resulting HTML will be streamed to the HTTP response.

var loginTemplate := template.Must(template.Parse(`
    <h1>Hello {{ .Username }}</h1>
`))

func LoginHandler(w http.ResponseWriter, req *http.Request) {
    response := respond.To(w, req)

    // ... do some work ...
    
    response.HTMLTemplate(loginTemplate, LoginContext{
        Username: username,
    })
}
FAQs
Why Not Just Use Gin/Chi/Echo/Fiber/Buffalo/etc?

If you want to use one of these to help you deal with writing HTTP responses, you also need to buy into their router, their request data binding, their middleware, their context objects, and so forth.

The respond package lets you stick to the standard library for all of your HTTP needs. In doing so, you can still bring your own router/mux, middleware, binding, etc. respond is solely focused on taking the "stank" out of marshaling data and writing response headers/data.

Do You Support Formats Other Than JSON

Nope. I've toyed with adding content negotiation so that if the caller is asking for XML they can get it. Realistically, if you jumped on the Go bandwagon to build HTTP service gateways you're likely using JSON anyway, so this one is fairly low priority.

Do You Support Other Template Engines for HTMLTemplate()?

Not directly. If you plan to call HTMLTemplate() then you have to use standard Go templates - which is sufficient for most use cases.

If you do use another template engine like Plush, you can just invoke its evaluation function yourself and pass the resulting HTML string to HTML(). It's not the most memory efficient, but it's probably more than sufficient for most workloads.

responder := respond.To(w, req)

ctx := plush.NewContext()
ctx.Set("username", "BobLoblaw")

html, err := plush.Render(loginTemplate, ctx)
responder.HTML(html, err)

You can even tighten this up more since Go will pass along the multiple return values properly:

responder := respond.To(w, req)

ctx := plush.NewContext()
ctx.Set("username", "BobLoblaw")

responder.HTML(plush.Render(loginTemplate, ctx))
There's No Function For The HTTP Status Code I Want To Send Back

To keep the library as lean and mean as possible, respond only has helpers for the most commonly used response status codes. If you absolutely must send an "I'm a Teapot" response, use the Reply() function.

responder := respond.To(w, req)
...
responder.Reply(http.StatusTeapot, "I'm a teapot")

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ContentFileNameReader added in v0.4.1

type ContentFileNameReader interface {
	// ContentFileName triggers an attachment-style value for the Content-Disposition header when writing
	// raw HTTP responses. When this returns an empty string, the response's disposition should
	// be "inline". When it's any other value, it will be "attachment; filename=" with this value.
	//
	// This only applies when the result is a ContentReader, so you're returning raw results.
	ContentFileName() string
}

ContentFileNameReader provides the 'filename' details to use when filling out the HTTP Content-Disposition header. Any io.Reader that 'respond' comes across will be treated as raw bytes, not a JSON-marshaled payload. By default, 'respond' will specify "inline" for all raw responses (great for images and scripts you want to display inline in your UI).

If you implement this interface, you can change the behavior to have the browser/client trigger a download of this asset instead. The file name you return here will dictate the default file name proposed by the save dialog.

type ContentReader added in v0.4.1

type ContentReader interface {
	// Content supplies the raw data that should be sent to the caller when responding.
	Content() io.ReadCloser
}

ContentReader indicates that the value you're responding with is actually raw byte content and not something that should be JSON-marshaled. The data read from the resulting io.Reader is what we will send back to the caller.

type ContentTypeReader added in v0.4.1

type ContentTypeReader interface {
	// ContentType returns the "Content-Type" header you want to apply to the HTTP response. This
	// only applies when the result is a ContentReader, so you're returning raw results.
	ContentType() string
}

ContentTypeReader provides details about a file-based response to indicate what we should use as the "Content-Type" header. Any io.Reader that 'respond' comes across will be treated as raw bytes, not a JSON-marshaled payload. By default, the Content-Type of the response will be "application/octet-stream", but if your result implements this interface, you can tell the responder what type to use instead. For instance, if the result is a JPG, you can have your result return "image/jpeg" and 'respond' will use that in the header instead of octet-stream.

type ErrorWithCode

type ErrorWithCode interface {
	error
	Code() int
}

ErrorWithCode is a type of error that contains a Code() function which indicates the HTTP 4XX/5XX status code this type of failure should respond with.

type ErrorWithStatus

type ErrorWithStatus interface {
	error
	Status() int
}

ErrorWithStatus is a type of error that contains a Status() function which indicates the HTTP 4XX/5XX status code this type of failure should respond with.

type ErrorWithStatusCode

type ErrorWithStatusCode interface {
	error
	StatusCode() int
}

ErrorWithStatusCode is a type of error that contains a StatusCode() function which indicates the HTTP 4XX/5XX status code this type of failure should respond with.

type Redirector

type Redirector interface {
	// Redirect returns the URL that you want the response to redirect to.
	Redirect() string
}

Redirector defines a type that your handler can "return" to one of the responder functions to indicate that this should be a redirect response instead of the standard 2XX style response you intended. This can also be used in general purpose Reply() calls to trigger redirects as well.

type Responder

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

Responder provides helper functions for marshaling Go values/streams to send back to the user as well as applying the correct status code and headers. It's the core data structure for this package.

func To

To creates a "Responder" that replies to the inputs for the given HTTP request. For style/consistency purposes, this should be the first line of your HTTP handler: `response := responder.To(w, req)`

Example (Basic)

A simple example. Format the string "Hello World" as JSON and respond to the caller with a 200 status code. We create a "Responder" for this request and then use it to respond with that result.

package main

import (
	"net/http"

	"github.com/monadicstack/respond"
)

func main() {
	_ = func(w http.ResponseWriter, req *http.Request) {
		respond.To(w, req).Ok("Hello World")
	}
}
Output:

Example (BusinessLogic)

You can return any primitive or complex value to the caller as JSON and respond with a 200. You focus on your business logic and responders offload the burden of marshalling, setting status code, and basic header application.

package main

import (
	"net/http"

	"github.com/monadicstack/respond"
)

func param(req *http.Request, name string) string {
	return ""
}

func findUser(id string) (map[string]interface{}, bool) {
	return nil, true
}

func main() {
	_ = func(w http.ResponseWriter, req *http.Request) {
		response := respond.To(w, req)

		userId := param(req, "user")
		user, ok := findUser(userId)
		if !ok {
			response.NotFound("user not found: %s", userId)
			return
		}
		response.Ok(user)
	}
}
Output:

Example (Error)

There are responder functions to support most of the common HTTP failures you typically encounter when building APIs/Services.

package main

import (
	"errors"
	"net/http"

	"github.com/monadicstack/respond"
)

var ErrNotFound = errors.New("not found")
var ErrBadCredentials = errors.New("bad credentials")
var ErrAuthorization = errors.New("authorization")

func doTask() (interface{}, error) {
	return nil, nil
}

func main() {
	_ = func(w http.ResponseWriter, req *http.Request) {
		response := respond.To(w, req)

		result, err := doTask()
		switch err {
		case nil:
			response.Ok(result)
		case ErrNotFound:
			response.NotFound("task not found")
		case ErrBadCredentials:
			response.Unauthorized("bad username/password")
		case ErrAuthorization:
			response.Forbidden("you don't have rights to do that")
		default:
			response.InternalServerError("unexpected error: %v", err)
		}
	}
}
Output:

Example (ErrorShorthand)

Success functions like Ok(), Accept(), etc optionally take an error (admittedly by bastardizing variadic arguments). If the error you pass is nil, the request will result in the 2XX status that you wanted w/ the return value. If the error is NOT nil then we'll respond with a 4XX/5XX status and the error's message instead.

We will attempt to assign a meaningful HTTP status code by unwrapping your non-nil error and look for one of three functions:

* Status() int * StatusCode() int * Code() int

We'll assume that the resulting int is the HTTP status code you want to fail with.

package main

import (
	"net/http"

	"github.com/monadicstack/respond"
)

func doTask() (interface{}, error) {
	return nil, nil
}

func main() {
	_ = func(w http.ResponseWriter, req *http.Request) {
		response := respond.To(w, req)

		// Option 1: pass the values separately
		result, err := doTask()
		response.Ok(result, err)

		// Option 2: pass the return values directly to your responder function
		response.Ok(doTask())
	}
}
Output:

Example (Middleware)

You can use respond with any standard middleware you want.

package main

import (
	"net/http"

	"github.com/monadicstack/respond"
)

func authenticate(req *http.Request) (*http.Request, error) {
	return nil, nil
}

func main() {
	_ = func(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
		response := respond.To(w, req)

		req, err := authenticate(req)
		if err != nil {
			response.Unauthorized(err.Error())
			return
		}

		next(w, req)
	}
}
Output:

func (Responder) Accepted

func (r Responder) Accepted(value interface{}, errs ...error)

Accepted writes a 202 style response to the caller by marshalling the given raw value. If you provided an error, we'll ignore the value and return the appropriate 4XX/5XX response instead.

func (Responder) BadGateway

func (r Responder) BadGateway(msg string, args ...interface{})

BadGateway responds w/ a 502 status and a body that contains the status/message.

func (Responder) BadRequest

func (r Responder) BadRequest(msg string, args ...interface{})

BadRequest responds w/ a 400 status and a body that contains the status/message.

func (Responder) Conflict

func (r Responder) Conflict(msg string, args ...interface{})

Conflict responds w/ a 409 status and a body that contains the status/message.

func (Responder) Created

func (r Responder) Created(value interface{}, errs ...error)

Created writes a 201 style response to the caller by marshalling the given raw value. If you provided an error, we'll ignore the value and return the appropriate 4XX/5XX response instead.

func (Responder) Download

func (r Responder) Download(fileName string, data io.Reader, errs ...error)

Download delivers the file data to the client/caller in a way that indicates that it should be given a download prompt (if using a browser or some other UI-based client). The file name determines the Content-Type header we'll use in the response as well as be the default download name that the caller will be presented with in their client/browser.

It will read your 'data' stream to completion but it will still be up to you to Close() it afterwards if need be.

func (Responder) DownloadBytes

func (r Responder) DownloadBytes(fileName string, data []byte, errs ...error)

DownloadBytes delivers the file data to the client/caller in a way that indicates that it should be given a download prompt (if using a browser or some other UI-based client). The file name determines the Content-Type header we'll use in the response as well as be the default download name that the caller will be presented with in their client/browser.

func (Responder) Fail

func (r Responder) Fail(err error)

Fail accepts the error generated by your handler and responds with the most appropriate 4XX/5XX status code and message for that error. It tries to unwrap the error looking for an error with either a Status(), StatusCode(), or Code() function (see the ErrorXXX interfaces in this package) to determine what HTTP status code we will try to fail with.

func (Responder) Forbidden

func (r Responder) Forbidden(msg string, args ...interface{})

Forbidden responds w/ a 403 status and a body that contains the status/message.

func (Responder) GatewayTimeout

func (r Responder) GatewayTimeout(msg string, args ...interface{})

GatewayTimeout responds w/ a 504 status and a body that contains the status/message.

func (Responder) Gone

func (r Responder) Gone(msg string, args ...interface{})

Gone responds w/ a 410 status and a body that contains the status/message.

func (Responder) HTML

func (r Responder) HTML(markup string, errs ...error)

HTML returns 200 status code with the given "text/html" response body. If you provided an error, we'll ignore the value and return the appropriate 4XX/5XX response instead.

func (Responder) HTMLTemplate

func (r Responder) HTMLTemplate(htmlTemplate *template.Template, ctxValue interface{}, errs ...error)

HTMLTemplate accepts your pre-parsed html template and evaluates it using the given context value. All of the bytes generated by the template will be written directly to the response writer. If you provided an error, we'll return the appropriate 4XX/5XX response instead.

func (Responder) InternalServerError

func (r Responder) InternalServerError(msg string, args ...interface{})

InternalServerError responds w/ a 500 status and a body that contains the status/message.

func (Responder) MethodNotAllowed

func (r Responder) MethodNotAllowed(msg string, args ...interface{})

MethodNotAllowed responds w/ a 405 status and a body that contains the status/message.

func (Responder) NoContent

func (r Responder) NoContent(errs ...error)

NoContent writes a 204 style response to the caller. This will not write any bytes to the response other than the status code. If you provided an error, we'll ignore the 204 and return the appropriate 4XX/5XX response instead.

func (Responder) NotFound

func (r Responder) NotFound(msg string, args ...interface{})

NotFound responds w/ a 404 status and a body that contains the status/message.

func (Responder) NotImplemented

func (r Responder) NotImplemented(msg string, args ...interface{})

NotImplemented responds w/ a 501 status and a body that contains the status/message.

func (Responder) NotModified

func (r Responder) NotModified(errs ...error)

NotModified writes a 304 response with no content. You typically will use this when performing ETag staleness checks and the like.

func (Responder) Ok

func (r Responder) Ok(value interface{}, errs ...error)

Ok writes a 200 style response to the caller by marshalling the given raw value. If you provided an error, we'll ignore the value and return the appropriate 4XX/5XX response instead.

func (Responder) Redirect

func (r Responder) Redirect(uriFormat string, args ...interface{})

Redirect performs a 307-style TEMPORARY redirect to the given resource. You can use printf-style formatting to make it easier to build the location you're redirecting to.

func (Responder) RedirectPermanent

func (r Responder) RedirectPermanent(uriFormat string, args ...interface{})

RedirectPermanent performs a 308-style PERMANENT redirect to the given resource. You can use printf-style formatting to make it easier to build the location you're redirecting to.

func (Responder) RedirectPermanentTo

func (r Responder) RedirectPermanentTo(redirector Redirector, errs ...error)

RedirectPermanentTo performs a 308-style PERMANENT redirect to the URL returned by calling Redirect() on your value.

func (Responder) RedirectTo

func (r Responder) RedirectTo(redirector Redirector, errs ...error)

RedirectTo performs a 307-style TEMPORARY redirect to the URL returned by calling Redirect() on your value.

func (Responder) Reply

func (r Responder) Reply(status int, value interface{}, errs ...error)

Reply lets you respond with the custom status code of your choice and a JSON-marshaled version of your value.

func (Responder) Serve

func (r Responder) Serve(fileName string, data io.Reader, errs ...error)

Serve responds with some sort of file data in an inline fashion. This lets you deliver things like inline images or videos or any other content that you want your callers/clients to embed directly in the client. The file name in this case case is simply used to determine the proper Content-Type to include in the response.

It will read your 'data' stream to completion but it will still be up to you to Close() it afterwards if need be.

func (Responder) ServeBytes

func (r Responder) ServeBytes(fileName string, data []byte, errs ...error)

ServeBytes responds with some sort of file data in an inline fashion. This lets you deliver things like inline images or videos or any other content that you want your callers/clients to embed directly in the client. The file name in this case case is simply used to determine the proper Content-Type to include in the response.

func (Responder) ServiceUnavailable

func (r Responder) ServiceUnavailable(msg string, args ...interface{})

ServiceUnavailable responds w/ a 503 status and a body that contains the status/message.

func (Responder) TooManyRequests

func (r Responder) TooManyRequests(msg string, args ...interface{})

TooManyRequests responds w/ a 429 status and a body that contains the status/message.

func (Responder) Unauthorized

func (r Responder) Unauthorized(msg string, args ...interface{})

Unauthorized responds w/ a 401 status and a body that contains the status/message.

Jump to

Keyboard shortcuts

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