I have this body structure in a POST
query:
{
"id": "019016a1-e00b-7e6f-ab3b-0d55f0c6bb4e",
"student_id": "01900cd1-ca56-724f-8b9b-fae26272380a",
"citation": {
"ISO-0012": {
"t": "11111111-1574-7646-9264-30e3be99e219",
"b": "22222222-1574-7646-9264-30e3be99e219"
}
}
}
My question, in a controller method, how to match and capture these as variables,
ISO-0012
as citation_id
t
as t
b
as b
?
citation_id
can have any value.
Thank you.
You probably cannot, because the citation_id key is not known at compile time (it is dynamic I guess)
1 Like
So I just have to move it inside the body ? at same level as t
and b
?
Yes, as a value, not a key
1 Like
As @kokolegorille says it’s not possible because the key is not known at compile time, but a partial solution would be the following:
json = ~S"""
{
"id": "019016a1-e00b-7e6f-ab3b-0d55f0c6bb4e",
"student_id": "01900cd1-ca56-724f-8b9b-fae26272380a",
"citation": {
"ISO-0012": {
"t": "11111111-1574-7646-9264-30e3be99e219",
"b": "22222222-1574-7646-9264-30e3be99e219"
}
}
}
"""
{:ok, parsed} = Jason.decode(json, keys: :strings, strings: :copy)
%{
"id" => _id,
"student_id" => _student_id,
"citation" => citation
} = parsed
citation_id = citation |> Map.keys() |> hd()
%{^citation_id => %{"b" => b, "t" => t}} = citation
And now you have citation_id
, t
and b
holding the right values.
It’s a bit clunky in your scenario but nothing that cannot be neatly wrapped. 
Or you can always use Access
, or (what I would do) a chain of Map.fetch
calls in a with
block. Up to you.
3 Likes
Slightly hacky and breaks if there’s ever multiple keys under the `“citation” map, but for fun:
iex(12)> json = ~S"""
...(12)> {
...(12)> "id": "019016a1-e00b-7e6f-ab3b-0d55f0c6bb4e",
...(12)> "student_id": "01900cd1-ca56-724f-8b9b-fae26272380a",
...(12)> "citation": {
...(12)> "ISO-0012": {
...(12)> "t": "11111111-1574-7646-9264-30e3be99e219",
...(12)> "b": "22222222-1574-7646-9264-30e3be99e219"
...(12)> }
...(12)> }
...(12)> }
...(12)> """
iex(14)> {:ok, parsed} = Jason.decode(json, keys: :strings, strings: :copy)
iex(15)> {citation_id, t, b} = Enum.find_value(parsed["citation"], fn {k, %{"t" => t, "b" => b}} -> {k, t, b} end)
{"ISO-0012", "11111111-1574-7646-9264-30e3be99e219",
"22222222-1574-7646-9264-30e3be99e219"}
iex(16)> citation_id
"ISO-0012"
iex(17)> t
"11111111-1574-7646-9264-30e3be99e219"
iex(18)> b
"22222222-1574-7646-9264-30e3be99e219"
2 Likes