responder

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2025 License: MIT Imports: 7 Imported by: 0

README

Responder Go Reference

A simple, flexible HTTP response handler for Go that provides a clean interface for sending various types of HTTP responses.

Features

  • Simple and intuitive API
  • Multiple content type support (JSON, HTML, CSV, Plain Text, XML)
  • Customizable error and content formatters

Installation

go get github.com/mickaelvieira/responder

Quick Start

package main

import (
    "net/http"
    "github.com/mickaelvieira/responder"
)

func main() {
    // Create a JSON responder
    jsonResp := responder.JSONResponder()

    http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
        // Send a successful response
        jsonResp.Send200(w, map[string]string{
            "name": "John Doe",
            "email": "john@example.com",
        })
        // or
        // jsonResp.Send(w, responder.Success(http.StatusOK, map[string]string{
        //     "name": "John Doe",
        //     "email": "john@example.com",
        // }))
    })

    http.HandleFunc("/api/error", func(w http.ResponseWriter, r *http.Request) {
        // Send an error response
        err := someFunction()
        if err != nil {
            jsonResp.Send400(w, err, "Invalid request")
            // or
            // jsonResp.Send(w, responder.Error(http.StatusBadRequest, err, "Invalid request"))
            return
        }
    })

    http.ListenAndServe(":8080", nil)
}

func someFunction() error {
    return nil
}

Available Responders

JSON Responder

Sends responses with application/json; charset=utf-8 content type. Error messages are automatically formatted as JSON objects.

resp := responder.JSONResponder()

// Success response
resp.Send200(w, map[string]any{
    "message": "Success",
    "data": []string{"item1", "item2"},
})

// Error response (automatically formatted as {"error": "Resource not found"})
resp.Send404(w, err, "Resource not found")
Text Responder

Sends plain text responses with text/plain; charset=utf-8 content type.

resp := responder.TextResponder()

resp.Send200(w, "Hello, World!")
resp.Send500(w, err, "Internal server error")
HTML Responder

Sends HTML responses with text/html; charset=utf-8 content type.

resp := responder.HTMLResponder()

resp.Send200(w, "<html><body><h1>Welcome</h1></body></html>")
resp.Send404(w, err, "<p>Page not found</p>")
CSV Responder

Sends CSV responses with text/csv; charset=utf-8 content type.

resp := responder.CSVResponder()

csvData := "name,age,city\nJohn,30,New York\nJane,25,London"
resp.Send200(w, csvData)
XML Responder

Sends XML responses with application/xml; charset=utf-8 content type.

resp := responder.XMLResponder()

xmlData := `<?xml version="1.0" encoding="UTF-8"?>
<user>
    <name>John Doe</name>
    <email>john@example.com</email>
</user>`
resp.Send200(w, xmlData)

Message Types

The error message parameter accepts any type, allowing you to pass various message formats:

String Messages
resp.Send400(w, err, "Invalid email format")
Error Messages
resp.Send500(w, err, err) // Pass the error itself as the message
Custom Struct Messages

With a custom ErrorFormatter, you can pass structured error messages:

type ErrorDetails struct {
    Code    string
    Message string
    Field   string
}

customFormatter := func(message any) any {
    switch v := message.(type) {
    case ErrorDetails:
        return fmt.Sprintf("Error %s: %s (field: %s)", v.Code, v.Message, v.Field)
    case error:
        return v.Error()
    default:
        return fmt.Sprint(message)
    }
}

resp := responder.TextResponder(responder.WithErrorFormatter(customFormatter))

// Pass a custom struct as the message
resp.Send400(w, err, ErrorDetails{
    Code:    "VALIDATION_001",
    Message: "Invalid input",
    Field:   "email",
})
JSON Error Messages

For JSON responses with custom error structures:

type JSONErrorResponse struct {
    Code      string   `json:"code"`
    Message   string   `json:"message"`
    Details   []string `json:"details"`
    Timestamp int64    `json:"timestamp"`
}

jsonContentFormatter := func(content any) []byte {
    data, _ := json.Marshal(content)
    return data
}

customFormatter := func(message any) any {
    switch v := message.(type) {
    case JSONErrorResponse:
        return v
    case error:
        return JSONErrorResponse{
            Code:      "ERROR",
            Message:   v.Error(),
            Timestamp: time.Now().Unix(),
        }
    default:
        return JSONErrorResponse{
            Code:      "ERROR",
            Message:   fmt.Sprint(message),
            Timestamp: time.Now().Unix(),
        }
    }
}

// Note: JSONResponder enforces {"error": "..."} format by default
// For custom JSON error structures, use New() with JSONContentType
resp := responder.New(responder.JSONContentType,
    responder.WithContentFormatter(jsonContentFormatter),
    responder.WithErrorFormatter(customFormatter),
)

resp.Send400(w, err, JSONErrorResponse{
    Code:    "VALIDATION_ERROR",
    Message: "Invalid request payload",
    Details: []string{"email is required", "password too short"},
    Timestamp: time.Now().Unix(),
})

Customization

With Logger

Add structured logging to your responder:

import "log/slog"

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
resp := responder.JSONResponder(responder.WithLogger(logger))

// Errors will be automatically logged
resp.Send500(w, err, "Database connection failed")
Custom Error Formatter

Customize how error messages are formatted. The formatter receives any type and returns any type:

customFormatter := func(message any) any {
    // Handle different message types
    switch v := message.(type) {
    case string:
        return map[string]any{
            "error":     v,
            "timestamp": time.Now().Unix(),
            "code":      "ERR_001",
        }
    case error:
        return map[string]any{
            "error":     v.Error(),
            "timestamp": time.Now().Unix(),
            "code":      "ERR_002",
        }
    default:
        return map[string]any{
            "error":     fmt.Sprint(v),
            "timestamp": time.Now().Unix(),
        }
    }
}

resp := responder.JSONResponder(responder.WithErrorFormatter(customFormatter))

Note: JSONResponder() applies a default formatter that wraps messages in {"error": "..."} format. To use fully custom JSON error structures, create a responder with responder.New() instead.

Custom Content Formatter

Customize how content is serialized:

customContentFormatter := func(content any) []byte {
    data, _ := json.MarshalIndent(content, "", "  ")
    return data
}

resp := responder.JSONResponder(responder.WithContentFormatter(customContentFormatter))
Combining Options

You can combine multiple options:

resp := responder.JSONResponder(
    responder.WithLogger(logger),
    responder.WithErrorFormatter(customErrorFormatter),
    responder.WithContentFormatter(customContentFormatter),
)

Advanced Usage

Creating Custom Responders
// Create a custom responder with a specific content type
customResp := responder.New("application/xml; charset=utf-8",
    responder.WithLogger(logger),
)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Documentation

Overview

Package responder provides a flexible and configurable way to send HTTP responses with different content types and status codes. It supports JSON, text, HTML, CSV, and XML responses, and allows customization of error message formatting and content formatting. It may be useful when writing web servers without a full-fledged web framework and avoid boilerplate code.

Index

Constants

View Source
const (
	// TextContentType is the content type for plain text responses
	TextContentType = "text/plain; charset=utf-8"
	// CSVContentType is the content type for CSV responses
	CSVContentType = "text/csv; charset=utf-8"
	// HTMLContentType is the content type for HTML responses
	HTMLContentType = "text/html; charset=utf-8"
	// JSONContentType is the content type for JSON responses
	JSONContentType = "application/json; charset=utf-8"
	// XMLContentType is the content type for XML responses
	XMLContentType = "application/xml; charset=utf-8"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type DataFormatter added in v0.2.0

type DataFormatter func(any) []byte

DataFormatter defines a function type for formatting the data before sending it in the response. It receives the original data as an any type and returns the formatted data as a []byte.

type ErrorFormatter

type ErrorFormatter func(any) any

ErrorFormatter defines a function type for formatting error messages before sending them in the response. It receives the original error message as any type and returns the formatted message as an any type. The output of this function is passed to the DataFormatter. The default error formatter converts the message to a string.

type ErrorResponse added in v0.2.0

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

ErrorResponse represents an HTTP response with status, message, and error.

func (ErrorResponse) Error added in v0.2.0

func (r ErrorResponse) Error() string

Error returns the internal error associated with the error response.

func (ErrorResponse) Status added in v0.2.0

func (r ErrorResponse) Status() int

Status returns the HTTP status code of the error response.

type OptionsModifier

type OptionsModifier func(*options)

OptionsModifier defines a function type for modifying Responder options.

func WithDataFormatter added in v0.2.0

func WithDataFormatter(f DataFormatter) OptionsModifier

WithDataFormatter sets a custom data formatter

func WithErrorFormatter

func WithErrorFormatter(f ErrorFormatter) OptionsModifier

WithErrorFormatter sets a custom error message formatter

func WithLogger

func WithLogger(l *slog.Logger) OptionsModifier

WithLogger sets a logger for the responder

type Responder

type Responder interface {
	// Send200 sends a 200 OK response.
	// It takes as second argument the data to be sent to the client.
	Send200(responseWriter, any)

	// Send201 sends a 201 Created response.
	// It takes as second argument the data to be sent to the client.
	Send201(responseWriter, any)

	// Send202 sends a 202 Accepted response.
	// It takes as second argument the data to be sent to the client.
	Send202(responseWriter, any)

	// Send204 sends a 204 No Content response.
	Send204(responseWriter)

	// Redirect301 sends a 301 Moved Permanently response to the given URL.
	Redirect301(responseWriter, *http.Request, string)

	// Redirect302 sends a 302 Found response to the given URL.
	Redirect302(responseWriter, *http.Request, string)

	// Redirect303 sends a 303 See Other response to the given URL.
	Redirect303(responseWriter, *http.Request, string)

	// Redirect307 sends a 307 Temporary Redirect response to the given URL.
	Redirect307(responseWriter, *http.Request, string)

	// Send400 sends a 400 Bad Request response. It takes as second argument
	// the error that caused the bad request, and as third argument a message
	// to be sent to the client.
	// The error will be logged if a logger was provided.
	Send400(responseWriter, error, any)

	// Send401 sends a 401 Unauthorized response. It takes as second argument
	// the error that caused the unauthorized response, and as third argument
	// a message to be sent to the client.
	// The error will be logged if a logger was provided.
	Send401(responseWriter, error, any)

	// Send403 sends a 403 Forbidden response. It takes as second argument
	// the error that caused the forbidden response, and as third argument
	// a message to be sent to the client.
	// The error will be logged if a logger was provided.
	Send403(responseWriter, error, any)

	// Send404 sends a 404 Not Found response. It takes as second argument
	// the error that caused the not found response, and as third argument
	// a message to be sent to the client.
	// The error will be logged if a logger was provided.
	Send404(responseWriter, error, any)

	// Send500 sends a 500 Internal Server Error response.
	// It takes as second argument the error that caused the
	// internal server error, and as third argument
	// a message to be sent to the client.
	// The error will be logged if a logger was provided.
	Send500(responseWriter, error, any)

	// Send sends a response with the given status code and body.
	Send(responseWriter, Response)
}

Responder defines the interface for sending HTTP responses.

func CSVResponder

func CSVResponder(options ...OptionsModifier) Responder

CSVResponder creates a new CSV responder.

func HTMLResponder

func HTMLResponder(options ...OptionsModifier) Responder

HTMLResponder creates a new HTML responder.

func JSONResponder

func JSONResponder(options ...OptionsModifier) Responder

JSONResponder creates a new JSON response handler. The Content-Type will be set to application/json with UTF-8 charset and the message will be formatted as a JSON error object { "error": string }.

func New

func New(contentType string, optionsModifiers ...OptionsModifier) Responder

New creates a new Responder with the given content type and options.

func TextResponder

func TextResponder(options ...OptionsModifier) Responder

TextResponder creates a new text responder.

func XMLResponder added in v0.1.3

func XMLResponder(options ...OptionsModifier) Responder

XMLResponder creates a new XML responder.

type Response added in v0.2.0

type Response interface {
	// Status returns the HTTP status code of the response.
	Status() int
}

Response represents an HTTP response with status, body, message, and error. It can be used to encapsulate both successful and error responses.

func Error added in v0.2.0

func Error(status int, err error, message string) Response

Error creates a new error Response with the given status code, message, and error. The message is intended to be sent to the client, while the error is for internal logging.

func Success added in v0.2.0

func Success(status int, body any) Response

Success creates a new successful Response with the given status code and body.

type SuccessResponse added in v0.2.0

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

SuccessResponse represents a successful HTTP response with status, body.

func (SuccessResponse) Status added in v0.2.0

func (r SuccessResponse) Status() int

Status returns the HTTP status code of the successful response.

Directories

Path Synopsis
Package internal contains utility functions used across the responder package that we do not want to expose publicly.
Package internal contains utility functions used across the responder package that we do not want to expose publicly.

Jump to

Keyboard shortcuts

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