To and from camelCase json api keys to snake_case elixir convention

I have an existing camelCase JSON API that I can’t change and I want to be able to continue to use elixir snake_case naming conventions. I am getting the JSON via UDP connection, and I send JSON responses back to that UDP endpoint. I am currently using Jason directly. It was included in the template, so I went with it. I figured out that I could provide my own decode function for keys so that I can change the JSON key to snake_case and run String.to_existing_atom/1. However this doesn’t appear to be an option in the encoding. I did find Convert camel case to underscore in json but it mostly talks about how to convert from camelCase to snake_case. It doesn’t talk about integrating into the JSON encoding. I could just recursively rebuild the entire struct into a map changing the keys, but that sounds like it would kill performance. Is there something I am missing? Should I just recursively convert each JSON payload I am sending? Should I switch to Poison? Should I not care about snake_case convention in Elixir?

I can relate to machine performance anxiety but I suggest you directly go this route and measure. Benchee will help.

Personally I’d go for:

def to_atom_map(%{
  "firstName" => first_name,
  "lastName" => last_name
%}) do
  %{
    first_name: first_name,
    last_name: last_name
  }
end

and vice versa.

You might enjoy checking out recase:

Here’s a quick script to show how you could use it

Mix.install([:recase, :jason])

Recase.Enumerable.convert_keys(
  %{"yourKey" => "value"},
  &Recase.to_snake/1
)
|> IO.inspect(label: "res")

json =
Recase.Enumerable.convert_keys(
  %{my_key: "value"},
  &Recase.to_camel/1
)
|> IO.inspect(label: "to camel")
|> Jason.encode!()

IO.puts("Json: #{json}")

Running this prints out:

res: %{"your_key" => "value"}
to camel: %{myKey: "value"}
Json: {"myKey":"value"}
2 Likes

Thanks everyone for replying. I was busy with work stuff and just got back to this thread.

@dimitarvp I will probably end up biting the bullet and writing/generating this code. I started switching over to typed_struct so I wonder if I couldn’t make a plugin to do it for me.

@axelson Recase looked like it could easily do what I wanted. The only thing I was worried about was that I couldn’t use the String.to_existing_atom so that the BEAM VM can’t get blown up by a malicious actor. I didn’t see one at least. I am pretty new to Elixir though so I could have missed something.

@mhanberg just released a new blog post and mentions his library schematic. Maybe that could help.
Here’s the Blog Post: Credo Language Server and the birth of elixir-tools | Mitchell Hanberg

1 Like

@kevinschweikert Schematic actually looks really cool. I might try it out later. I feel like I will just need to experiment with all these solutions.