Convert a nested struct into a nested map

Another option is to use Nestru. It supports transformation in both ways. Encoding from nested struct into a map can be like the following.

defmodule Nadia.Model.Chat do
  @derive Nestru.Encoder
  defstruct [:first_name, :id, :last_name, :photo, :title, :type, :username]
end

defmodule Nadia.Model.User do
  @derive Nestru.Encoder
  defstruct [:first_name, :id, :last_name, :username]
end

defmodule Nadia.Model.Message do
  @derive Nestru.Encoder
  defstruct [
    :audio,
    :caption,
    :channel_chat_created,
    :chat,
    :contact,
    :date,
    :delete_chat_photo,
    :document,
    :edit_date,
    :entities,
    :forward_date,
    :forward_from,
    :forward_from_chat,
    :from,
    :group_chat_created,
    :left_chat_member,
    :location,
    :message_id,
    :migrate_from_chat_id,
    :migrate_to_chat_id,
    :new_chat_member,
    :new_chat_photo,
    :new_chat_title,
    :photo,
    :pinned_message,
    :reply_to_message,
    :sticker,
    :supergroup_chat_created,
    :text,
    :venue,
    :video,
    :voice
  ]
end

struct = %{
  callback_query: nil,
  channel_post: nil,
  chosen_inline_result: nil,
  edited_message: nil,
  inline_query: nil,
  message: %Nadia.Model.Message{
    audio: nil,
    caption: nil,
    channel_chat_created: nil,
    chat: %Nadia.Model.Chat{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      photo: nil,
      title: nil,
      type: "private",
      username: "ChristianTovar"
    },
    contact: nil,
    date: 1562605521,
    delete_chat_photo: nil,
    document: nil,
    edit_date: nil,
    entities: nil,
    forward_date: nil,
    forward_from: nil,
    forward_from_chat: nil,
    from: %Nadia.Model.User{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      username: "ChristianTovar"
    },
    group_chat_created: nil,
    left_chat_member: nil,
    location: nil,
    message_id: 714,
    migrate_from_chat_id: nil,
    migrate_to_chat_id: nil,
    new_chat_member: nil,
    new_chat_photo: [],
    new_chat_title: nil,
    photo: [],
    pinned_message: nil,
    reply_to_message: nil,
    sticker: nil,
    supergroup_chat_created: nil,
    text: "google meets",
    venue: nil,
    video: nil,
    voice: nil
  },
  update_id: 412827321
}

encoding looks like:

iex> Nestru.to_map(struct)
{:ok,
 %{
   callback_query: nil,
   channel_post: nil,
   chosen_inline_result: nil,
   edited_message: nil,
   inline_query: nil,
   message: %{
     audio: nil,
     caption: nil,
     channel_chat_created: nil,
     chat: %{
       first_name: "Christian",
       id: 543211234,
       last_name: "Tovar",
       photo: nil,
       title: nil,
       type: "private",
       username: "ChristianTovar"
     },
     contact: nil,
     date: 1562605521,
     delete_chat_photo: nil,
     document: nil,
     edit_date: nil,
     entities: nil,
     forward_date: nil,
     forward_from: nil,
     forward_from_chat: nil,
     from: %{first_name: "Christian", id: 543211234, last_name: "Tovar", username: "ChristianTovar"},
     group_chat_created: nil,
     left_chat_member: nil,
     location: nil,
     message_id: 714,
     migrate_from_chat_id: nil,
     migrate_to_chat_id: nil,
     new_chat_member: nil,
     new_chat_photo: [],
     new_chat_title: nil,
     photo: [],
     pinned_message: nil,
     reply_to_message: nil,
     sticker: nil,
     supergroup_chat_created: nil,
     text: "google meets",
     venue: nil,
     video: nil,
     voice: nil
   },
   update_id: 412827321
 }}