A powerful command-line tool that generates Go structs from JSON with comprehensive multi-format tag support (JSON, YAML, XML) and advanced customization options.
- Converts JSON from files or stdin to Go structs
- Interactive mode for quick, ad-hoc conversions
- Intelligent type detection including UUIDs and timestamps
- Handles complex nested objects and arrays
- Formats output according to Go standards
- JSON tags: Standard Go JSON serialization tags
- YAML tags: Generate YAML-compatible struct tags
- XML tags: Generate XML serialization tags
- Simultaneous generation: Create multiple tag formats at once
- Configuration files: Use
.gotyper.ymlfor project-specific settings - Pattern-based field customization: Apply custom tag options using regex patterns
- Field skipping: Exclude sensitive or internal fields from struct generation
- Type mappings: Map specific field patterns to custom Go types
- Naming conventions: Customize field and struct naming rules
- Tag customization: Control omitempty, field exclusion, and custom serialization options
go install github.com/mcncl/gotyper@latest# From a file
gotyper -i input.json -o output.go
# From stdin
cat input.json | gotyper > output.go
# Interactive mode (just run gotyper with no arguments)
gotyper
# Then paste your JSON and press Ctrl+D (or Ctrl+Z on Windows) when done -i, --input=STRING Path to input JSON file. If not specified, reads from stdin.
-o, --output=STRING Path to output Go file. If not specified, writes to stdout.
-p, --package=STRING Package name for generated code. (default: main)
-r, --root-name=STRING Name for the root struct. (default: RootType)
-c, --config=STRING Path to configuration file. If not specified, searches for .gotyper.yml
-f, --format Format the output code according to Go standards. (default: true)
-d, --debug Enable debug logging.
-v, --version Show version information.
-I, --interactive Run in interactive mode, allowing direct JSON input with Ctrl+D to process.
GoTyper supports YAML configuration files for advanced customization. The tool automatically searches for .gotyper.yml, .gotyper.yaml, gotyper.yml, or gotyper.yaml in the current directory and parent directories.
Example Configuration: See
.gotyper.example.ymlfor a comprehensive configuration example with all available options.
Create a .gotyper.yml file in your project root:
package: "models"
root_name: "APIResponse"
# Generate multiple tag formats
json_tags:
omitempty_for_pointers: true
omitempty_for_slices: true
additional_tags:
- "yaml"
- "xml"package: "models"
root_name: "APIResponse"
# Type mappings for consistent field types
types:
mappings:
- pattern: ".*_id$|^id$"
type: "int64"
comment: "Database ID"
- pattern: "created_at|updated_at|.*_time$"
type: "time.Time"
import: "time"
comment: "Timestamp"
# Custom field naming
naming:
pascal_case_fields: true
field_mappings:
"user_id": "UserID"
"api_key": "APIKey"
"url": "URL"
# Enhanced tag generation
json_tags:
omitempty_for_pointers: true
omitempty_for_slices: true
additional_tags:
- "yaml"
- "xml"
# Pattern-based tag customization
custom_options:
- pattern: "password.*|.*secret.*"
options: "-"
comment: "Sensitive field - excluded from JSON"
- pattern: ".*_count$|.*_total$"
options: "omitempty,string"
comment: "Numeric field serialized as string"
# Fields to skip entirely
skip_fields:
- "internal_use_only"
- "debug_info"The --root-name flag allows you to specify a custom name for the root struct:
# Generate a struct named "User" instead of "RootType"
gotyper -i user.json -r UserWhen processing JSON objects, this name is used directly:
{
"name": "John",
"email": "[email protected]"
}With --root-name=User generates:
type User struct {
Email string `json:"email"`
Name string `json:"name"`
}When processing arrays at the root level, the root name is automatically singularized to name the struct for array elements:
[
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
]With --root-name=Items generates:
type Item struct { // Note: 'Items' is singularized to 'Item'
ID int64 `json:"id"`
Name string `json:"name"`
}The --package flag sets the package declaration in the generated Go file:
# Generate code for a specific package
gotyper -i data.json -p modelsBy default, GoTyper formats the output code according to Go standards. You can disable this with --format=false:
# Disable automatic formatting
gotyper -i data.json --format=falseFor quick, ad-hoc conversions without creating temporary files:
- Run
gotyperwith no arguments (or with the-Iflag) - Paste your JSON data at the prompt
- Press Ctrl+D (Unix/Mac) or Ctrl+Z followed by Enter (Windows) to signal the end of input
- The generated Go structs will be displayed immediately
Input JSON:
{
"name": "John Doe",
"age": 30,
"email": "[email protected]",
"is_active": true,
"created_at": "2023-01-01T12:00:00Z",
"address": {
"street": "123 Main St",
"city": "Anytown",
"zip": "12345"
},
"tags": ["developer", "golang"],
"scores": [98, 87, 95]
}Output Go Code (default):
package main
import (
"time"
)
type Address struct {
City string `json:"city"`
Street string `json:"street"`
Zip string `json:"zip"`
}
type RootType struct {
Address *Address `json:"address,omitempty"`
Age int64 `json:"age"`
CreatedAt time.Time `json:"created_at"`
Email string `json:"email"`
IsActive bool `json:"is_active"`
Name string `json:"name"`
Scores []int64 `json:"scores,omitempty"`
Tags []string `json:"tags,omitempty"`
}Configuration (.gotyper.yml):
package: "models"
root_name: "User"
json_tags:
additional_tags:
- "yaml"
- "xml"
custom_options:
- pattern: ".*email.*"
options: "omitempty"
comment: "Email address"Enhanced Output:
package models
import (
"time"
)
type Address struct {
City string `json:"city" yaml:"city" xml:"city"`
Street string `json:"street" yaml:"street" xml:"street"`
Zip string `json:"zip" yaml:"zip" xml:"zip"`
}
type User struct {
Address *Address `json:"address,omitempty" yaml:"address" xml:"address"`
Age int64 `json:"age" yaml:"age" xml:"age"`
CreatedAt time.Time `json:"created_at" yaml:"created_at" xml:"created_at"`
Email string `json:"email,omitempty" yaml:"email" xml:"email"` // Email address
IsActive bool `json:"is_active" yaml:"is_active" xml:"is_active"`
Name string `json:"name" yaml:"name" xml:"name"`
Scores []int64 `json:"scores,omitempty" yaml:"scores" xml:"scores"`
Tags []string `json:"tags,omitempty" yaml:"tags" xml:"tags"`
}Configuration:
package: "api"
root_name: "Response"
types:
mappings:
- pattern: ".*_id$"
type: "int64"
comment: "Database ID"
naming:
field_mappings:
"user_id": "UserID"
"api_key": "APIKey"
json_tags:
additional_tags: ["yaml"]
custom_options:
- pattern: ".*secret.*|.*password.*"
options: "-"
comment: "Sensitive data excluded from serialization"
- pattern: ".*_count$"
options: "omitempty,string"
skip_fields:
- "internal_debug_info"Input JSON:
{
"user_id": 123,
"api_key": "sk-1234567890",
"password_hash": "hashed_password",
"view_count": 42,
"internal_debug_info": "debug data"
}Generated Go Code:
package api
type Response struct {
APIKey string `json:"api_key" yaml:"api_key"`
PasswordHash string `json:"password_hash,-" yaml:"password_hash"` // Sensitive data excluded from serialization
UserID int64 `json:"user_id" yaml:"user_id"` // Database ID
ViewCount int64 `json:"view_count,omitempty,string" yaml:"view_count"`
// Note: internal_debug_info field is completely excluded
}GoTyper automatically detects appropriate Go types based on the JSON data:
- Strings β
string - Numbers β
int64(for integers) orfloat64(for decimals) - Booleans β
bool - Null β pointer types with
omitemptytag - Objects β custom struct types
- Arrays β slices of appropriate types
- Enhanced Time Detection β
time.Time - UUIDs (e.g.,
123e4567-e89b-12d3-a456-426614174000) βstring
GoTyper includes comprehensive time format detection that recognizes various timestamp formats commonly found in real-world APIs and data sources:
ISO8601 and RFC3339 Formats:
2023-01-15T14:30:00Z(RFC3339)2023-01-15T14:30:00.123456789Z(RFC3339 with nanoseconds)2023-01-15T14:30:00+05:30(ISO8601 with timezone)20230115T143000Z(ISO8601 basic format)2023-W03-1T10:30:00Z(ISO8601 week date)2023-015T10:30:00Z(ISO8601 ordinal date)
Date-Only Formats:
2023-01-15(ISO date)2023.01.15(dot-separated)20230115(compact format)
US Date Formats:
01/15/2023or1/15/2023(MM/DD/YYYY)01-15-2023or1-15-2023(MM-DD-YYYY)
European Date Formats:
15/01/2023or15/1/2023(DD/MM/YYYY)15-01-2023or15-1-2023(DD-MM-YYYY)15.01.2023or15.1.2023(DD.MM.YYYY)
Time-Only Formats:
14:30:15or14:30(24-hour format)2:30:15 PMor2:30 pm(12-hour format with AM/PM)
Month Name Formats:
January 15, 2023orJan 15, 2023(US style)15 January 2023(European style)
Unix Timestamps:
- Unix timestamps (seconds and milliseconds) are kept as
int64by default for flexibility - Use
unix_timestamps_as_time: truein configuration to convert them totime.Time
DateTime with Space:
2023-01-15 14:30:00(space-separated date and time)
When processing JSON arrays, GoTyper analyzes the elements to determine the most appropriate slice type:
- Arrays of primitives (strings, numbers, booleans) β slices of the corresponding Go type
- Arrays of objects β slices of a custom struct type
- Empty arrays β
[]interface{}withomitemptytag - Mixed-type arrays β
[]interface{}
Fields that contain null in the JSON are converted to pointer types with the omitempty JSON tag. For example:
{
"name": "John",
"address": null
}Becomes:
type RootType struct {
Address *Address `json:"address,omitempty"`
Name string `json:"name"`
}GoTyper provides clear error messages for common issues:
- Empty input: "empty input received"
- Invalid JSON syntax: detailed parsing errors with position information
- File not found: "failed to open file ''"
- Multiple JSON values at root: "multiple JSON values at root level not supported"
- Permission issues: "failed to write to file ''"
When an error occurs, GoTyper will display a user-friendly message and exit with a non-zero status code.
# Basic settings
package: "models" # Go package name
root_name: "APIResponse" # Name for root struct
# Code formatting
formatting:
enabled: true # Enable gofmt formatting
use_gofumpt: false # Use gofumpt instead of gofmt
# Type inference and mapping
types:
force_int64: false # Force all integers to int64
optional_as_pointers: true # Make nullable fields pointers
unix_timestamps_as_time: false # Convert Unix timestamps to time.Time instead of int64
mappings:
- pattern: ".*_id$|^id$" # Regex pattern for field names
type: "int64" # Target Go type
import: "" # Additional import if needed
comment: "Database ID" # Comment for generated field
# Field naming conventions
naming:
pascal_case_fields: true # Convert snake_case to PascalCase
field_mappings: # Custom field name mappings
"user_id": "UserID"
"api_key": "APIKey"
# JSON tag generation
json_tags:
omitempty_for_pointers: true # Add omitempty to pointer fields
omitempty_for_slices: true # Add omitempty to slice fields
additional_tags: # Additional tag formats to generate
- "yaml"
- "xml"
custom_options: # Pattern-based tag customization
- pattern: "password.*" # Field pattern
options: "-" # Tag options (-, omitempty, string, etc.)
comment: "Excluded field" # Comment for field
skip_fields: # Fields to exclude entirely
- "internal_use_only"
- "debug_info"
# Validation tags (if implemented)
validation:
enabled: false # Enable validation tag generation
rules:
- pattern: ".*email.*"
tag: "validate:\"required,email\""
# Output options
output:
file_header: "" # Custom file header
generate_constructors: false # Generate constructor functions
generate_string_methods: false # Generate String() methods
# Array handling
arrays:
merge_different_objects: true # Merge objects with different fields
singularize_names: true # Singularize array element struct names
# Development options
dev:
debug: false # Enable debug output
verbose: false # Enable verbose loggingGenerate structs that work with multiple serialization formats:
# Create a config file for multi-format output
cat > .gotyper.yml << EOF
json_tags:
additional_tags:
- "yaml"
- "xml"
- "toml"
EOF
# Generate structs with multiple tag formats
curl -s https://api.example.com/data | gotyper -p modelsCreate project-specific configurations for different APIs:
# GitHub API configuration
cat > github.gotyper.yml << EOF
package: "github"
root_name: "Repository"
types:
mappings:
- pattern: ".*_at$"
type: "time.Time"
import: "time"
naming:
field_mappings:
"html_url": "HTMLURL"
"ssh_url": "SSHURL"
json_tags:
custom_options:
- pattern: ".*token.*"
options: "-"
comment: "Sensitive - excluded from JSON"
EOF
# Use specific config
gotyper -i github_response.json -c github.gotyper.ymlAutomatically handle sensitive fields:
# security-focused.gotyper.yml
json_tags:
custom_options:
# Exclude all password/secret/token fields
- pattern: ".*password.*|.*secret.*|.*token.*|.*key$"
options: "-"
comment: "Sensitive data - excluded from JSON serialization"
# Mark PII fields for careful handling
- pattern: ".*email.*|.*phone.*|.*ssn.*"
options: "omitempty"
comment: "PII - handle with care"
skip_fields:
- "internal_id"
- "debug_trace"
- "raw_sql"# Quick API exploration
curl -s https://api.example.com/users/123 | gotyper -I# Add to your project
gotyper -i api_response.json -o internal/models/user.go -p models -r User
# With project-specific config
gotyper -i api_response.json -o models/api.go -c .gotyper.yml# Validate generated code compiles
gotyper -i schema.json -o /tmp/test.go && go build /tmp/test.go
# Generate and format in one step
gotyper -i data.json | gofmt > models/generated.goMIT