Maxximiliann
This proof of concept periodically polls data from a specific API before decoding the JSON. It should create a list of atoms from the binary keys it receives the first time it queries the API for reuse with each subsequent poll.
defmodule ProofOfConcept do
def naive_string_to_atom(raw_json) do
{:ok, decoded_api_response} = Jason.decode(raw_json)
root_keys =
decoded_api_response
|> List.first()
|> Map.keys()
nested_keys =
Enum.flat_map(
root_keys,
fn key ->
decoded_api_response
|> Enum.map(fn map_element ->
foo = Map.get(map_element, key)
case is_map(foo) do
true ->
Map.keys(foo)
false ->
:not_a_key
end
end)
|> Enum.reject(&(&1 == :not_a_key))
end
)
|> Enum.flat_map(& &1)
|> Enum.uniq()
extracted_keys =
(nested_keys ++ root_keys)
|> Enum.map(&String.to_atom(&1))
IO.inspect(extracted_keys, limit: :infinity)
end
def decode(raw_json) do
try do
Jason.decode(raw_json, keys: :atoms!)
rescue
_ ->
IO.puts("Converting JSON keys to atoms . . . ")
naive_string_to_atom(raw_json)
main()
end
end
def main() do
api_url = "https://wavescap.com/api/assets.json"
{:ok, api_response} = HTTPoison.get(api_url)
decode(api_response.body)
end
end
The problem:
Apparently the atomized keys are never retained in memory, requiring them to be recreated each time updated data is retrieved from the API.
iex(1)> ProofOfConcept.main
Converting JSON keys to atoms . . .
[:firstPrice_brln, :firstPrice_btc, :firstPrice_cnyn, :firstPrice_eth,
:firstPrice_eurn, :firstPrice_gbpn, :firstPrice_jpyn, :firstPrice_ngnn,
:firstPrice_rubn, :firstPrice_tryn, :firstPrice_uahn, :"firstPrice_usd-n",
:firstPrice_waves, :lastPrice_brln, :lastPrice_btc, :lastPrice_cnyn,
:lastPrice_eth, :lastPrice_eurn, :lastPrice_gbpn, :lastPrice_jpyn,
:lastPrice_ngnn, :lastPrice_rubn, :lastPrice_tryn, :lastPrice_uahn,
:"lastPrice_usd-n", :lastPrice_waves, :"24h_vol_brln", :"24h_vol_btc",
:"24h_vol_cnyn", :"24h_vol_eth", :"24h_vol_eurn", :"24h_vol_gbpn",
:"24h_vol_jpyn", :"24h_vol_ngnn", :"24h_vol_rubn", :"24h_vol_tryn",
:"24h_vol_uahn", :"24h_vol_usd-n", :"24h_vol_waves", :circulating, :data,
:excludedFromCirculating, :id, :name, :precision, :sender, :shortcode, :start,
:totalSupply, :trades, :website]
Converting JSON keys to atoms . . .
[:firstPrice_brln, :firstPrice_btc, :firstPrice_cnyn, :firstPrice_eth,
:firstPrice_eurn, :firstPrice_gbpn, :firstPrice_jpyn, :firstPrice_ngnn,
:firstPrice_rubn, :firstPrice_tryn, :firstPrice_uahn, :"firstPrice_usd-n",
:firstPrice_waves, :lastPrice_brln, :lastPrice_btc, :lastPrice_cnyn,
:lastPrice_eth, :lastPrice_eurn, :lastPrice_gbpn, :lastPrice_jpyn,
:lastPrice_ngnn, :lastPrice_rubn, :lastPrice_tryn, :lastPrice_uahn,
:"lastPrice_usd-n", :lastPrice_waves, :"24h_vol_brln", :"24h_vol_btc",
:"24h_vol_cnyn", :"24h_vol_eth", :"24h_vol_eurn", :"24h_vol_gbpn",
:"24h_vol_jpyn", :"24h_vol_ngnn", :"24h_vol_rubn", :"24h_vol_tryn",
:"24h_vol_uahn", :"24h_vol_usd-n", :"24h_vol_waves", :circulating, :data,
:excludedFromCirculating, :id, :name, :precision, :sender, :shortcode, :start,
:totalSupply, :trades, :website]
Converting JSON keys to atoms . . .
[:firstPrice_brln, :firstPrice_btc, :firstPrice_cnyn, :firstPrice_eth,
:firstPrice_eurn, :firstPrice_gbpn, :firstPrice_jpyn, :firstPrice_ngnn,
:firstPrice_rubn, :firstPrice_tryn, :firstPrice_uahn, :"firstPrice_usd-n",
:firstPrice_waves, :lastPrice_brln, :lastPrice_btc, :lastPrice_cnyn,
:lastPrice_eth, :lastPrice_eurn, :lastPrice_gbpn, :lastPrice_jpyn,
:lastPrice_ngnn, :lastPrice_rubn, :lastPrice_tryn, :lastPrice_uahn,
:"lastPrice_usd-n", :lastPrice_waves, :"24h_vol_brln", :"24h_vol_btc",
:"24h_vol_cnyn", :"24h_vol_eth", :"24h_vol_eurn", :"24h_vol_gbpn",
:"24h_vol_jpyn", :"24h_vol_ngnn", :"24h_vol_rubn", :"24h_vol_tryn",
:"24h_vol_uahn", :"24h_vol_usd-n", :"24h_vol_waves", :circulating, :data,
:excludedFromCirculating, :id, :name, :precision, :sender, :shortcode, :start,
:totalSupply, :trades, :website]
Converting JSON keys to atoms . . .
[:firstPrice_brln, :firstPrice_btc, :firstPrice_cnyn, :firstPrice_eth,
:firstPrice_eurn, :firstPrice_gbpn, :firstPrice_jpyn, :firstPrice_ngnn,
:firstPrice_rubn, :firstPrice_tryn, :firstPrice_uahn, :"firstPrice_usd-n",
:firstPrice_waves, :lastPrice_brln, :lastPrice_btc, :lastPrice_cnyn,
:lastPrice_eth, :lastPrice_eurn, :lastPrice_gbpn, :lastPrice_jpyn,
:lastPrice_ngnn, :lastPrice_rubn, :lastPrice_tryn, :lastPrice_uahn,
:"lastPrice_usd-n", :lastPrice_waves, :"24h_vol_brln", :"24h_vol_btc",
:"24h_vol_cnyn", :"24h_vol_eth", :"24h_vol_eurn", :"24h_vol_gbpn",
:"24h_vol_jpyn", :"24h_vol_ngnn", :"24h_vol_rubn", :"24h_vol_tryn",
:"24h_vol_uahn", :"24h_vol_usd-n", :"24h_vol_waves", :circulating, :data,
:excludedFromCirculating, :id, :name, :precision, :sender, :shortcode, :start,
:totalSupply, :trades, :website]
Converting JSON keys to atoms . . .
[:firstPrice_brln, :firstPrice_btc, :firstPrice_cnyn, :firstPrice_eth,
:firstPrice_eurn, :firstPrice_gbpn, :firstPrice_jpyn, :firstPrice_ngnn,
:firstPrice_rubn, :firstPrice_tryn, :firstPrice_uahn, :"firstPrice_usd-n",
:firstPrice_waves, :lastPrice_brln, :lastPrice_btc, :lastPrice_cnyn,
:lastPrice_eth, :lastPrice_eurn, :lastPrice_gbpn, :lastPrice_jpyn,
:lastPrice_ngnn, :lastPrice_rubn, :lastPrice_tryn, :lastPrice_uahn,
:"lastPrice_usd-n", :lastPrice_waves, :"24h_vol_brln", :"24h_vol_btc",
:"24h_vol_cnyn", :"24h_vol_eth", :"24h_vol_eurn", :"24h_vol_gbpn",
:"24h_vol_jpyn", :"24h_vol_ngnn", :"24h_vol_rubn", :"24h_vol_tryn",
:"24h_vol_uahn", :"24h_vol_usd-n", :"24h_vol_waves", :circulating, :data,
:excludedFromCirculating, :id, :name, :precision, :sender, :shortcode, :start,
:totalSupply, :trades, :website]
After each new API poll, why aren’t the atoms that were previously generated being reused?
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
Hi all,
I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
I’m very new to Elixir, so sorry if this is a silly question:
I am wondering what happens to the mailbox of a process when the machine i...
New
How do I tell Hologram not to escape HTML when substituting into templates?
{Textile.render(@product.long_description)}
escapes the HTM...
New
Background
When trying to execute mix release on a Windows 11 machine for a Phoenix project I get the following error:
* assembling mark...
New
Hi,
we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
I’d like to create a file with 600 permissions (rw-------), but there’s a race condition if I create it and then change the permissions. ...
New
Other Trending Topics
Hey there,
I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first.
...
New
Hi everyone :waving_hand:
I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly)
AI dream has many faces, but general...
New
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #code-sync
- #discussion
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #elixirconf-us
- #podcasts-by-brainlid
- #blog-post
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #elixirconf-eu
- #processes
- #security
- #api
- #forms
- #performance










Showing Posts 1 to 4- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
al2o3cr
If one of the elements of
decoded_api_responsehas additional keys not present in the first one,naive_string_to_atomwill not see them and the bug you’re seeing would happen.The error message here should be helpful - on OTP 25, it is explicit about what string failed:
Maxximiliann
Per your suggestion I made the following update:
Outcome:
It seems it’s trying to atomize new lines? Am I reading this right?
al2o3cr
The message in the
ArgumentErroris only the top half of the output from triggering that error iniex- the other half is from__STACKTRACE__:Maxximiliann
The API is not universally constructed, as it turns out, so some records have keys that are absent from others. I was able to deduce what was going wrong and rewrite the code to accommodate for it thanks to being able to examine the error stacktrace. Thanks for the tip!
Btw, please elaborate on a few of the points you made here when you have a moment to spare, thanks again!