response

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 3 Imported by: 0

README

Response - Consistent API Response Utilities

A lightweight package for creating consistent JSON API responses with a standard format (code, data, error). Provides convenient helper functions for common HTTP status codes and response patterns.

Installation

go get github.com/davidsugianto/go-pkgs/response

Quick Start

package main

import (
    "net/http"
    "github.com/davidsugianto/go-pkgs/response"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // Success response
    response.Success(w, map[string]string{"message": "Hello"})
    
    // Error response
    response.BadRequest(w, errors.New("invalid input"))
}

Features

  • Standard Format - Consistent code, data, error response structure
  • Type-Safe - Helper functions for common HTTP status codes
  • Simple API - Clean, intuitive functions for all response types
  • Flexible - Support for custom status codes and messages
  • Zero Dependencies - Uses only standard library (Gin support optional)
  • Gin Framework - Built-in support for Gin web framework (via build tag)

Response Format

All responses follow this standard JSON format:

{
  "code": 200,
  "data": { ... },
  "error": "..."
}
  • code: HTTP status code (always present)
  • data: Response payload (omitted if empty)
  • error: Error message (omitted if empty)

Usage

Success Responses
Success(w, data) - Status 200 OK
user := User{ID: 1, Name: "John"}
response.Success(w, user)

// Response:
// {
//   "code": 200,
//   "data": {"id": 1, "name": "John"}
// }
Created(w, data) - Status 201 Created
newUser := User{ID: 2, Name: "Jane"}
response.Created(w, newUser)

// Response:
// {
//   "code": 201,
//   "data": {"id": 2, "name": "Jane"}
// }
NoContent(w) - Status 204 No Content
response.NoContent(w)

// Response: Empty body with 204 status
Error Responses
BadRequest(w, err) - Status 400
response.BadRequest(w, errors.New("invalid input"))

// Response:
// {
//   "code": 400,
//   "error": "invalid input"
// }
Unauthorized(w, err) - Status 401
response.Unauthorized(w, errors.New("authentication required"))

// Response:
// {
//   "code": 401,
//   "error": "authentication required"
// }
Forbidden(w, err) - Status 403
response.Forbidden(w, errors.New("access denied"))

// Response:
// {
//   "code": 403,
//   "error": "access denied"
// }
NotFound(w, err) - Status 404
response.NotFound(w, errors.New("user not found"))

// Response:
// {
//   "code": 404,
//   "error": "user not found"
// }
InternalServerError(w, err) - Status 500
response.InternalServerError(w, errors.New("database error"))

// Response:
// {
//   "code": 500,
//   "error": "database error"
// }
Custom Responses
JSON(w, statusCode, data) - Custom Status Code
// Any status code with data
response.JSON(w, http.StatusAccepted, map[string]string{
    "message": "Request accepted",
})

// Response:
// {
//   "code": 202,
//   "data": {"message": "Request accepted"}
// }
Error(w, statusCode, err) - Custom Error Status
// Custom error status code
response.Error(w, http.StatusConflict, errors.New("resource exists"))

// Response:
// {
//   "code": 409,
//   "error": "resource exists"
// }
StatusCode(w, statusCode, message) - Custom Status with Message
response.StatusCode(w, http.StatusTeapot, "I'm a teapot")

// Response:
// {
//   "code": 418,
//   "error": "I'm a teapot"
// }

Complete Example

package main

import (
	"errors"
	"net/http"

	"github.com/davidsugianto/go-pkgs/response"
)

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

func getUserHandler(w http.ResponseWriter, r *http.Request) {
	userID := r.URL.Query().Get("id")
	if userID == "" {
		response.BadRequest(w, errors.New("id parameter required"))
		return
	}

	// Simulate fetching user
	user, err := fetchUser(userID)
	if err != nil {
		response.NotFound(w, err)
		return
	}

	response.Success(w, user)
}

func createUserHandler(w http.ResponseWriter, r *http.Request) {
	var user User
	if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
		response.BadRequest(w, err)
		return
	}

	// Validate user
	if user.Name == "" || user.Email == "" {
		response.BadRequest(w, errors.New("name and email are required"))
		return
	}

	// Create user
	newUser, err := saveUser(user)
	if err != nil {
		response.InternalServerError(w, err)
		return
	}

	response.Created(w, newUser)
}

func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
	userID := r.URL.Query().Get("id")
	if err := deleteUser(userID); err != nil {
		if err == ErrUserNotFound {
			response.NotFound(w, err)
		} else {
			response.InternalServerError(w, err)
		}
		return
	}

	response.NoContent(w)
}

func main() {
	http.HandleFunc("/users", getUserHandler)
	http.HandleFunc("/users/create", createUserHandler)
	http.HandleFunc("/users/delete", deleteUserHandler)

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

Response Structure

The Response struct is available if you need to construct responses manually:

type Response struct {
    Code  int         `json:"code"`
    Data  interface{} `json:"data,omitempty"`
    Error string      `json:"error,omitempty"`
}

Example:

resp := Response{
    Code: 200,
    Data: map[string]string{"message": "success"},
}

json.NewEncoder(w).Encode(resp)

Error Handling

All response functions return an error (typically from JSON encoding). It's good practice to handle these:

if err := response.Success(w, data); err != nil {
    log.Printf("Failed to write response: %v", err)
    // Response may have been partially written
}

However, in most cases, JSON encoding errors are rare and can be logged rather than causing a panic.

Best Practices

  1. Use Appropriate Status Codes

    • Use Success() for successful GET/PUT/PATCH requests
    • Use Created() for successful POST requests
    • Use NoContent() for successful DELETE requests
  2. Error Messages

    • Provide clear, user-friendly error messages
    • Avoid exposing internal implementation details
  3. Data Types

    • Use structs for structured data
    • Use maps for simple key-value pairs
    • Use slices for arrays
  4. Consistency

    • Always use the response package for API responses
    • Maintain consistent error message format

API Reference

Functions
JSON(w http.ResponseWriter, statusCode int, data interface{}) error

Writes a JSON response with the given status code and data.

Success(w http.ResponseWriter, data interface{}) error

Writes a success JSON response with status 200 OK.

Created(w http.ResponseWriter, data interface{}) error

Writes a success JSON response with status 201 Created.

NoContent(w http.ResponseWriter)

Writes an empty response with status 204 No Content.

Error(w http.ResponseWriter, statusCode int, err error) error

Writes an error JSON response with the given status code and error message.

BadRequest(w http.ResponseWriter, err error) error

Writes a 400 Bad Request error response.

Unauthorized(w http.ResponseWriter, err error) error

Writes a 401 Unauthorized error response.

Forbidden(w http.ResponseWriter, err error) error

Writes a 403 Forbidden error response.

NotFound(w http.ResponseWriter, err error) error

Writes a 404 Not Found error response.

InternalServerError(w http.ResponseWriter, err error) error

Writes a 500 Internal Server Error response.

StatusCode(w http.ResponseWriter, statusCode int, message string) error

Writes a JSON response with the given status code and message string.

Examples

See the example/ directory for a complete working example.

cd example
go run main.go

Then try the endpoints:

  • GET http://localhost:8080/success
  • GET http://localhost:8080/created
  • GET http://localhost:8080/not-found
  • GET http://localhost:8080/bad-request
  • GET http://localhost:8080/internal-error
  • GET http://localhost:8080/no-content
  • GET http://localhost:8080/custom

Gin Framework Support

The package includes built-in support for the Gin web framework.

Installation
go get github.com/gin-gonic/gin
Usage
package main

import (
    "errors"
    "github.com/gin-gonic/gin"
    "github.com/davidsugianto/go-pkgs/response"
)

func getUser(c *gin.Context) {
    user := User{ID: 1, Name: "John"}
    response.GinSuccess(c, user)
}

func createUser(c *gin.Context) {
    var user User
    if err := c.ShouldBindJSON(&user); err != nil {
        response.GinBadRequest(c, err)
        return
    }
    response.GinCreated(c, user)
}

func deleteUser(c *gin.Context) {
    if err := deleteUserByID(c.Param("id")); err != nil {
        response.GinNotFound(c, err)
        return
    }
    response.GinNoContent(c)
}

func main() {
    r := gin.Default()
    r.GET("/users/:id", getUser)
    r.POST("/users", createUser)
    r.DELETE("/users/:id", deleteUser)
    r.Run(":8080")
}
Gin API Reference

All Gin functions accept *gin.Context as the first parameter:

Function Status Code Description
GinJSON(c, code, data) Custom Custom status with data
GinSuccess(c, data) 200 Success response
GinCreated(c, data) 201 Resource created
GinNoContent(c) 204 No content
GinError(c, code, err) Custom Custom error status
GinBadRequest(c, err) 400 Bad request error
GinUnauthorized(c, err) 401 Unauthorized error
GinForbidden(c, err) 403 Forbidden error
GinNotFound(c, err) 404 Not found error
GinInternalServerError(c, err) 500 Server error
GinStatusCode(c, code, msg) Custom Custom status with message
GinPaginated(c, data, page, size, total) 200 Paginated response
Paginated Response
func listUsers(c *gin.Context) {
    users := []User{
        {ID: 1, Name: "John"},
        {ID: 2, Name: "Jane"},
    }
    response.GinPaginated(c, users, 1, 10, 25)
}

// Response:
// {
//   "code": 200,
//   "data": [...],
//   "page": 1,
//   "page_size": 10,
//   "total": 25
// }

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BadRequest

func BadRequest(w http.ResponseWriter, err error) error

func Created

func Created(w http.ResponseWriter, data interface{}) error

func Error

func Error(w http.ResponseWriter, statusCode int, err error) error

func Forbidden

func Forbidden(w http.ResponseWriter, err error) error

func GinBadRequest added in v1.0.1

func GinBadRequest(c *gin.Context, err error)

GinBadRequest sends a bad request error (400 Bad Request)

func GinCreated added in v1.0.1

func GinCreated(c *gin.Context, data interface{})

GinCreated sends a created JSON response (201 Created)

func GinError added in v1.0.1

func GinError(c *gin.Context, statusCode int, err error)

GinError sends an error JSON response

func GinForbidden added in v1.0.1

func GinForbidden(c *gin.Context, err error)

GinForbidden sends a forbidden error (403 Forbidden)

func GinInternalServerError added in v1.0.1

func GinInternalServerError(c *gin.Context, err error)

GinInternalServerError sends an internal server error (500 Internal Server Error)

func GinJSON added in v1.0.1

func GinJSON(c *gin.Context, statusCode int, data interface{})

GinJSON sends a JSON response with the given status code and data

func GinNoContent added in v1.0.1

func GinNoContent(c *gin.Context)

GinNoContent sends a no content response (204 No Content)

func GinNotFound added in v1.0.1

func GinNotFound(c *gin.Context, err error)

GinNotFound sends a not found error (404 Not Found)

func GinPaginated added in v1.0.1

func GinPaginated(c *gin.Context, data interface{}, page, pageSize, total int)

GinPaginated sends a paginated JSON response

func GinStatusCode added in v1.0.1

func GinStatusCode(c *gin.Context, statusCode int, message string)

GinStatusCode sends a response with a custom status code and message

func GinSuccess added in v1.0.1

func GinSuccess(c *gin.Context, data interface{})

GinSuccess sends a successful JSON response (200 OK)

func GinUnauthorized added in v1.0.1

func GinUnauthorized(c *gin.Context, err error)

GinUnauthorized sends an unauthorized error (401 Unauthorized)

func InternalServerError

func InternalServerError(w http.ResponseWriter, err error) error

func JSON

func JSON(w http.ResponseWriter, statusCode int, data interface{}) error

func NoContent

func NoContent(w http.ResponseWriter)

func NotFound

func NotFound(w http.ResponseWriter, err error) error

func StatusCode

func StatusCode(w http.ResponseWriter, statusCode int, message string) error

func Success

func Success(w http.ResponseWriter, data interface{}) error

func Unauthorized

func Unauthorized(w http.ResponseWriter, err error) error

Types

type PaginatedResponse added in v1.0.1

type PaginatedResponse struct {
	Code     int         `json:"code"`
	Data     interface{} `json:"data,omitempty"`
	Page     int         `json:"page"`
	PageSize int         `json:"page_size"`
	Total    int         `json:"total"`
}

PaginatedResponse represents a paginated API response

type Response

type Response struct {
	Code  int         `json:"code"`
	Data  interface{} `json:"data,omitempty"`
	Error string      `json:"error,omitempty"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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