Documentation
¶
Overview ¶
Package json provides case-sensitive JSON unmarshaling functionality.
Unlike the standard encoding/json package which performs case-insensitive field matching, this package requires exact field name matches (respecting json tags).
This is particularly useful when:
- You need strict validation of JSON field names
- There's a risk of duplicate fields with different cases
- You want to ensure only exact field matches are accepted
- You're building APIs that require rigorous validation
Basic Usage:
import (
stdjson "encoding/json"
csjson "github.com/go-mg/casesensitive/json"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
payload := `{"name":"john", "NAME":"doe", "email":"john@example.com"}`
// Standard encoding/json (case-insensitive)
var user1 User
stdjson.Unmarshal([]byte(payload), &user1)
// Result: user1.Name = "doe" (last value wins)
// casesensitive/json (case-sensitive)
var user2 User
csjson.Unmarshal([]byte(payload), &user2)
// Result: user2.Name = "john" (only exact "name" match)
Decoder with Strict Validation:
decoder := csjson.NewDecoder(strings.NewReader(payload)) decoder.DisallowUnknownFields() err := decoder.Decode(&user) // Returns error: json: unknown field "NAME"
JSON Tags Support:
The package respects json tags the same way as encoding/json:
type User struct {
Name string `json:"name"` // Maps to "name"
Email string `json:"email"` // Maps to "email"
Password string `json:"-"` // Ignored
Age int `json:"age,omitempty"` // Maps to "age"
Nickname string // No tag: maps to "Nickname" (exact)
}
Performance Considerations:
This package is slightly slower than encoding/json due to additional validation. Use encoding/json when performance is critical and case-sensitivity is not required.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Unmarshal ¶
Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. Unlike standard json.Unmarshal, this function is case-sensitive at all nesting levels and will only match exact field names (respecting json tags). v can be a pointer to a struct or a pointer to a slice of structs.
Example ¶
package main
import (
"fmt"
"github.com/go-mg/casesensitive/json"
)
func main() {
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
payload := `{"name":"john", "NAME":"hacker", "email":"john@example.com"}`
var user User
if err := json.Unmarshal([]byte(payload), &user); err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Name: %s\n", user.Name)
fmt.Printf("Email: %s\n", user.Email)
}
Output: Name: john Email: john@example.com
Example (Array) ¶
package main
import (
"fmt"
"github.com/go-mg/casesensitive/json"
)
func main() {
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
}
payload := `[{"id":1,"name":"first"},{"id":2,"name":"second"}]`
var items []Item
if err := json.Unmarshal([]byte(payload), &items); err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, item := range items {
fmt.Printf("ID: %d, Name: %s\n", item.ID, item.Name)
}
}
Output: ID: 1, Name: first ID: 2, Name: second
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder reads and decodes JSON values from an input stream with case-sensitive field matching.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/go-mg/casesensitive/json"
)
func main() {
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
payload := `{"name":"john","email":"john@example.com"}`
var user User
decoder := json.NewDecoder(strings.NewReader(payload))
err := decoder.Decode(&user)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Name: %s\n", user.Name)
fmt.Printf("Email: %s\n", user.Email)
}
Output: Name: john Email: john@example.com
Example (DisallowUnknownFields) ¶
package main
import (
"fmt"
"strings"
"github.com/go-mg/casesensitive/json"
)
func main() {
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
payload := `{"name":"john","NAME":"hacker","email":"john@example.com"}`
var user User
decoder := json.NewDecoder(strings.NewReader(payload))
decoder.DisallowUnknownFields()
err := decoder.Decode(&user)
fmt.Printf("Error: %v\n", err)
}
Output: Error: json: unknown field "NAME"
Example (TrailingDataRejected) ¶
package main
import (
"fmt"
"strings"
"github.com/go-mg/casesensitive/json"
)
func main() {
type User struct {
Name string `json:"name"`
}
payload := `{"name":"john"}extra_data`
var user User
decoder := json.NewDecoder(strings.NewReader(payload))
err := decoder.Decode(&user)
fmt.Printf("Error: %v\n", err)
}
Output: Error: json: invalid character after top-level value
func NewDecoder ¶
NewDecoder returns a new decoder that reads from r.
func (*Decoder) AllowTrailingData ¶
AllowTrailingData allows the Decoder to accept input with data after the JSON value. By default, the decoder rejects trailing data to prevent injection attacks. Use this only when you need to parse multiple JSON values from a stream.
func (*Decoder) Decode ¶
Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v. Unlike standard json.Decoder, this decoder is case-sensitive and validates that the entire input is valid JSON without trailing data (unless AllowTrailingData is called). v can be a pointer to a struct or a pointer to a slice of structs.
func (*Decoder) DisallowUnknownFields ¶
DisallowUnknownFields causes the Decoder to return an error when the destination is a struct and the input contains object keys which do not match any non-ignored, exported fields in the destination (case-sensitive).
func (*Decoder) More ¶
More returns true if there is another element in the current array or object being parsed.