Skip to content

Repository files navigation

Rescode - Type-Safe Go Error Code Generator

Go ReferenceGo Report CardLicense: MIT

Rescode Logo

Rescode is a robust, MIT-licensed, open-source Go code generator that produces type-safe error code constants and error creator functions from user-supplied JSON or YAML configuration. The generated code follows Go best practices, works seamlessly with go:generate, and enables high-performance, compile-time validated error handling without any runtime map/slice lookups.

🎯 Motivation

Traditional error handling in Go often involves:

  • Runtime map lookups for error metadata
  • String-based error codes prone to typos
  • Inconsistent error response formats
  • No compile-time validation
  • Poor performance due to runtime lookups

Rescode solves these problems by generating type-safe, compile-time constants and factory functions that provide:

  • Zero runtime lookups - All metadata is compile-time constants
  • Type safety - No magic strings or runtime errors
  • High performance - Up to 140x faster than map-based approaches
  • Consistent API - Standardized error handling across services
  • HTTP/gRPC ready - Built-in status code mapping

🚀 Features

  • Type-safe error constants - Generate compile-time validated error codes
  • Factory functions - Simple, consistent error creation API
  • YAML/JSON input - Flexible configuration format with auto-detection
  • HTTP/gRPC integration - Built-in status code mapping
  • Error wrapping - Preserve original errors with full stack traces
  • Additional data - Attach structured data to errors
  • go:generate compatible - Seamless integration with Go toolchain
  • High performance - No runtime maps or lookups
  • Comprehensive tests - >95% test coverage with benchmarks
  • CLI tool - Simple command-line interface

📦 Installation

go get github.com/restayway/rescode

🛠️ Quick Start

1. Define your errors (YAML)

Create an errors.yaml file:

- code: 1001key: UserNotFoundmessage: User not foundhttp: 404grpc: 5desc: The specified user could not be found in the database
- code: 1002key: InvalidEmailmessage: Invalid email addresshttp: 400grpc: 3desc: The provided email address is not valid

2. Generate Go code

go run github.com/restayway/rescode/cmd/rescodegen --input errors.yaml --output errors_gen.go --package main

Or use go:generate:

//go:generate go run github.com/restayway/rescode/cmd/rescodegen --input errors.yaml --output errors_gen.go --package main

3. Use the generated errors

package main
import (
"fmt""log"
)
funcmain() {
// Create simple errorerr:=UserNotFound()
fmt.Printf("Error: %v (HTTP: %d, gRPC: %d)\n", err, err.HttpCode, err.RpcCode)
// Create error with wrapped errororiginalErr:=fmt.Errorf("database connection failed")
wrappedErr:=UserNotFound(originalErr)
fmt.Printf("Wrapped: %v\n", wrappedErr)
fmt.Printf("Original: %v\n", wrappedErr.OriginalError())
// Add additional dataenrichedErr:=InvalidEmail().SetData(map[string]string{
"field": "email",
"value": "invalid@",
})
fmt.Printf("JSON: %v\n", enrichedErr.JSON())
// Use constants for logiciferr.Code==UserNotFoundCode {
log.Printf("Handling user not found error with code %d", UserNotFoundCode)
}
}

📋 Error Definition Schema

YAML Format

- code: 1001# Required: Unique numeric error code (uint64)key: UserNotFound # Required: Go identifier for the errormessage: User not found # Required: Human-readable error messagehttp: 404# Required: HTTP status codegrpc: 5# Required: gRPC status code (0-16)desc: Description # Optional: Detailed description for documentation

JSON Format

[
{
"code": 1001,
"key": "UserNotFound",
"message": "User not found",
"http": 404,
"grpc": 5,
"desc": "The specified user could not be found in the database"
}
]

Field Validation

  • code: Must be non-zero unique uint64
  • key: Must be valid Go identifier (PascalCase recommended)
  • message: Non-empty human-readable string
  • http: Valid HTTP status code (typically 400-599)
  • grpc: Valid gRPC status code (0-16)
  • desc: Optional description for documentation

gRPC Status Code Reference

CodegRPC StatusDescription
0OKSuccess
1CANCELLEDOperation cancelled
2UNKNOWNUnknown error
3INVALID_ARGUMENTInvalid argument
4DEADLINE_EXCEEDEDDeadline exceeded
5NOT_FOUNDNot found
6ALREADY_EXISTSAlready exists
7PERMISSION_DENIEDPermission denied
8RESOURCE_EXHAUSTEDResource exhausted
9FAILED_PRECONDITIONFailed precondition
10ABORTEDAborted
11OUT_OF_RANGEOut of range
12UNIMPLEMENTEDUnimplemented
13INTERNALInternal error
14UNAVAILABLEUnavailable
15DATA_LOSSData loss
16UNAUTHENTICATEDUnauthenticated

🎯 Generated Code

For the example above, rescode generates:

// Code generated by rescodegen. DO NOT EDIT.package main
import (
"github.com/restayway/rescode""google.golang.org/grpc/codes"
)
// Error code constantsconst (
UserNotFoundCodeuint64=1001UserNotFoundHTTPint=404UserNotFoundGRPC codes.Code=5UserNotFoundMsgstring="User not found"UserNotFoundDescstring="The specified user could not be found in the database"InvalidEmailCodeuint64=1002InvalidEmailHTTPint=400InvalidEmailGRPC codes.Code=3InvalidEmailMsgstring="Invalid email address"InvalidEmailDescstring="The provided email address is not valid"
)
// UserNotFound creates a new UserNotFound error.// The specified user could not be found in the databasefuncUserNotFound(err...error) *rescode.RC {
returnrescode.New(UserNotFoundCode, UserNotFoundHTTP, UserNotFoundGRPC, UserNotFoundMsg)(err...)
}
// InvalidEmail creates a new InvalidEmail error.// The provided email address is not validfuncInvalidEmail(err...error) *rescode.RC {
returnrescode.New(InvalidEmailCode, InvalidEmailHTTP, InvalidEmailGRPC, InvalidEmailMsg)(err...)
}

🏃‍♂️ CLI Usage

rescodegen [OPTIONS]
Options:
--input Path to YAML/JSON file containing error definitions (required)
--output Path to generated Go file (default: rescode_gen.go)
--package Go package name to use in generated code (default: directory name)
--version Show version information
--help Show help information
Examples:
rescodegen --input errors.yaml --output errors_gen.go --package myservice
go run github.com/restayway/rescode/cmd/rescodegen --input errors.json
For go:generate usage:
//go:generate go run github.com/restayway/rescode/cmd/rescodegen --input errors.yaml --output errors_gen.go --package myservice

🔧 API Reference

Core Types

typeRCstruct {
Codeuint64// Unique error codeMessagestring// Human-readable error messageHttpCodeint// HTTP status codeRpcCode codes.Code// gRPC status codeDataany// Optional additional data
}
typeRcCreatorfunc(...error) *RC

Core Functions

// New creates an RcCreator function with the specified parametersfuncNew(codeuint64, hCodeint, rCode codes.Code, messagestring, data...any) RcCreator// Error implements the error interfacefunc (r*RC) Error() string// SetData sets additional data for the error and returns the RC for chainingfunc (r*RC) SetData(dataany) *RC// JSON returns a map representation of the error, optionally filtering by keysfunc (r*RC) JSON(keys...string) map[string]interface{}
// OriginalError returns the wrapped original error, if anyfunc (r*RC) OriginalError() error// String returns a string representation of the errorfunc (r*RC) String() string

📊 Performance Benchmarks

This library implements multiple error handling approaches in Go. The benchmarks below compare their performance on an Apple M4 Pro (arm64):

ApproachDescription
GeneratedCompile-time optimized (current)
LegacyRuntime map lookup
StaticCodeStatic constants + maps
VarCodeVariable declarations + maps

Benchmark Metrics

  • ns/op: nanoseconds per operation (lower is better)
  • B/op: bytes allocated per operation (lower is better)
  • allocs/op: allocations per operation (lower is better)

Leaderboard: Fastest Results per Test

TestBest ApproachBest ns/opB/opallocs/opNotes
PolicyNotFoundGenerated0.227600Over 70x faster than next best, 0 alloc
MultipleErrorsGenerated0.423100Over 40x faster than next best, 0 alloc
ErrorMessageGenerated0.237700Orders of magnitude faster, 0 alloc
JSONVarCode111.03846All approaches within 4 ns/op of each other

Raw Benchmark Results

Expand for full benchmark output
go test -bench="PolicyNotFound$|MultipleErrors$|ErrorMessage$|JSON$" -benchmem -count=5
goos: darwin
goarch: arm64
cpu: Apple M4 Pro
PolicyNotFound
Generated 0.2276 ns/op 0 B/op 0 allocs/op
Legacy 19.30 ns/op 80 B/op 1 allocs/op
StaticCode 17.52 ns/op 80 B/op 1 allocs/op
VarCode 18.15 ns/op 80 B/op 1 allocs/op
MultipleErrors
Generated 0.4231 ns/op 0 B/op 0 allocs/op
Legacy 20.44 ns/op 80 B/op 1 allocs/op
StaticCode 19.28 ns/op 80 B/op 1 allocs/op
VarCode 19.13 ns/op 80 B/op 1 allocs/op
ErrorMessage
Generated 0.2377 ns/op 0 B/op 0 allocs/op
Legacy 9.365 ns/op 0 B/op 0 allocs/op
StaticCode 9.525 ns/op 0 B/op 0 allocs/op
VarCode 9.547 ns/op 0 B/op 0 allocs/op
JSON
Generated 112.0 ns/op 384 B/op 6 allocs/op
Legacy 111.4 ns/op 384 B/op 6 allocs/op
StaticCode 112.5 ns/op 384 B/op 6 allocs/op
VarCode 111.0 ns/op 384 B/op 6 allocs/op

Observations

  • The Generated (compile-time) approach is orders of magnitude faster for simple error creation, with zero allocations.
  • For error messages, all static approaches (Legacy/StaticCode/VarCode) are very close in performance.
  • For JSON serialization, all approaches perform nearly identically, limited by Go’s native map/interface allocation and JSON encoding overhead.
  • In typical usage, any of these approaches is fast enough; only in high-throughput or critical-path code will the differences matter.

Tip: If you require both dynamic error construction and zero-allocation performance, prefer the Generated approach for hot paths. For API/JSON serialization, all approaches have similar performance due to Go’s encoding/json design.

🏗️ Examples

Basic Usage

See examples/basic/ for a complete basic example.

Microservice Integration

See examples/microservice/ for a full HTTP service example with error handling.

Key features demonstrated:

  • HTTP status code mapping
  • JSON error responses
  • Error data attachment
  • Error wrapping
  • Type-safe error handling

🧪 Testing

Run tests with coverage:

go test -v -cover ./...

Run benchmarks:

go test -bench=. -benchmem

The project maintains >95% test coverage with comprehensive tests for:

  • Core error functionality
  • Code generation
  • CLI tool
  • Generated code validation
  • Performance benchmarks

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup

  1. Clone the repository
  2. Run tests: go test ./...
  3. Run benchmarks: go test -bench=.
  4. Generate examples: cd examples/basic && go generate

Code Standards

  • Follow Go best practices and idioms
  • Maintain test coverage >95%
  • Include benchmarks for performance-critical code
  • Update documentation for API changes

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Inspired by the need for type-safe, high-performance error handling in Go
  • Built with Go's excellent tooling ecosystem
  • Thanks to the Go community for feedback and suggestions

Made with ❤️ for the Go community

About

Custom error code generator focused on performance and customization

Resources

Code of conduct

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages