Fabi755
Fabi755

Reputation: 1514

Limit fields of JSON response

I'm using the PhoenixFramework and the library Poison. Current I'm working on an REST API. Now I need to encode the model Book in two different ways.

  1. In a list of all books with only base informations (GET /books)
  2. In a detailed view with all informations (GET /book/1)

GET /books

{
  "books": [
    {
      "id": 1,
      "name": "Book one"
    },
    {
      "id": 2,
      "name": "Book two"
    },
    // ...
  ]
}

GET /books/1

{
  "book": {
     "id": 1,
     "name": "Book one",
     "description": "This is book one.",
     "author": "Max Mustermann",
    // ...
  }
}

Encoder of Book

defimpl Poison.Encoder, for: MyProject.Book do

  @attributes [:id, :name, :description, :author]

  def encode(project, _options) do
    project
    |> Map.take(@attributes)
    |> Poison.encode!
  end
end

Snippet controller

def index(conn, _params) do
  books = Repo.all(Book)
  json(conn, %{books: books})
end

How to limit the fields? I search for a option like :only or :exclude. Has anyone experience with this problem?

Thanks for help!

Upvotes: 2

Views: 525

Answers (1)

Gazler
Gazler

Reputation: 84180

You can use render_many/4 and render_one/4:

defmodule MyApp.BookView do

  def render("index.json", %{books: books}) do
    render_many(books, __MODULE__, "book.json")
  end

  def render("show.json", %{book: book}) do
    render_one(book, __MODULE__, "full_book.json")
  end

  def render("book.json", %{book: book}) do
    %{
      id: book.id,
      name: book.name
    }
  end


  def render("full_book.json", %{book: book}) do
    %{
      id: book.id,
      name: book.name,
      description: description,
      author: book.author
      ...
    }
  end
end

Please note that the name in assigns (2nd argument of render) is determined by the module. See Render many to many relationship JSON in Phoenix Framework for an example of using a different name.

You can then call this from your controller using:

render(conn, "index.json", books: Repo.all(Book))

render(conn, "show.json", book: Repo.get(Book, 1))

Upvotes: 5

Related Questions