Skip to content

Instantly share code, notes, and snippets.

@Rican7
Last active November 27, 2023 07:10
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Rican7/39a3dc10c1499384ca91 to your computer and use it in GitHub Desktop.
Save Rican7/39a3dc10c1499384ca91 to your computer and use it in GitHub Desktop.
Marshal JSON in Golang using common lower-snake-case object key conventions
package main
import (
"bytes"
"encoding/json"
"fmt"
"regexp"
"time"
)
// Regexp definitions
var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
var wordBarrierRegex = regexp.MustCompile(`(\w)([A-Z])`)
type conventionalMarshaller struct {
Value interface{}
}
func (c conventionalMarshaller) MarshalJSON() ([]byte, error) {
marshalled, err := json.Marshal(c.Value)
converted := keyMatchRegex.ReplaceAllFunc(
marshalled,
func(match []byte) []byte {
return bytes.ToLower(wordBarrierRegex.ReplaceAll(
match,
[]byte(`${1}_${2}`),
))
},
)
return converted, err
}
type exampleModel struct {
Title string
Description string
CreatedAt time.Time
UpdatedAt time.Time
IsActive bool
}
func main() {
model := exampleModel{
Title: "Example Title",
Description: "whatever",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
IsActive: true,
}
encoded, _ := json.MarshalIndent(conventionalMarshaller{model}, "", " ")
fmt.Println(string(encoded))
}
@Rican7
Copy link
Author

Rican7 commented Nov 18, 2015

Output

{
  "title": "Example Title",
  "description": "whatever",
  "created_at": "2015-11-17T20:43:31.046357698-05:00",
  "updated_at": "2015-11-17T20:43:31.046359788-05:00",
  "is_active": true
}

@bezigon
Copy link

bezigon commented Mar 30, 2017

How about "is_ur_l" for "IsURL" field? Or "is_ur_lactive" for "IsURLActive"?
I expected to have "is_url" and "is_url_active" respectively.

@edwardstudy
Copy link

edwardstudy commented Aug 17, 2017

@bezigon Maybe that's also work.

@glassonion1
Copy link

glassonion1 commented Dec 6, 2017

(\w)([A-Z]) -> ([a-z_0-9])([A-Z])

@piersy
Copy link

piersy commented Feb 9, 2018

This is actually outputting snake case, I've uploaded a gist giving lower camel case here https://gist.github.com/piersy/b9934790a8892db1a603820c0c23e4a7

@Rican7
Copy link
Author

Rican7 commented Jan 16, 2019

Soooo, I know its been 3+ years and all, but I've turned this kind of behavior into a proper package:
https://github.com/Rican7/conjson

It incorporates both snake_case and camelCase transformations, among others. 😃

Thanks for the comments, suggestions, and forks on this original Gist everyone!

@Rican7
Copy link
Author

Rican7 commented Jan 16, 2019

@Rican7
Copy link
Author

Rican7 commented Jun 3, 2019

@Nyura95
Copy link

Nyura95 commented Mar 6, 2020

Nice, thx !
It works very well.

I just change your regex for (\w{2,})([A-Z]).

I have interface with the key ID and your regex transform this in i_d
If someone has a better way :)

@Rican7
Copy link
Author

Rican7 commented Mar 6, 2020

@Nyura95 try checking out this project instead:
https://github.com/Rican7/conjson

It's an expansion on this idea. 😃

@soufi
Copy link

soufi commented Mar 21, 2021

Nice ! Thank you for sharing !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment