View Source Carve
DSL for building JSON APIs fast. Creates endpoint views, renders linked data automatically.
Features:
- Rendering structured JSON views automatically
- Retrieving links between different data types
- Creating index/show methods for views
- Encoding and decoding IDs (w/ unique salt per data type) using HashIds
Example endpoint view generated by Carve:
{
"result": {
"id": "D3Wcorr0oa",
"type": "user",
"data": { ... }
},
"links": [
{
"id": "Xk9Lp2Rr4m",
"type": "team",
"data": { ... }
},
{
"id": "Bz7Jt5Yq1n",
"type": "profile",
"data": { ... }
}
]
}
Installation
Add carve
to your list of dependencies in mix.exs
:
def deps do
[
{:carve, "~> 0.1.0"}
]
end
To configure custom hashing salt, add to config.exs
:
config :carve,
salt: "your-secret-salt",
min_length: 10
Usage
In your Phoenix JSON view, just declare how your endpoint should look like:
defmodule UserJSON do
use Carve.View, :user
view fn user ->
%{
id: hash(user.id), # provided by Carve.View, encodes numerical ID (123) with an entity-specific salt (D3Wcorr0oa).
name: user.name
}
end
end
And that's it -- this macro will make index(%{ result: users })
and show(%{ result: user })
methods available for your controller.
Of course, just formatting the view alone is not Carvers only point; you can declare the links of each view, and Carve will automatically output them for the client:
defmodule UserJSON do
use Carve.View, :user
# Return the links of a given user
links fn user ->
%{
FooWeb.TeamJSON => user.team_id,
FooWeb. ProfileJSON => user.profile_id
}
end
# Provide a method to retrieve user by id. This will be used by Carve to render links automatically.
get fn id ->
Foo.Users.get_by_id!(id)
end
view fn user ->
%{
id: hash(user.id),
team_id: FooWeb.TeamJSON.hash(user.team_id),
profile_id: FooWeb.ProfileJSON.hash(user.profile_id),
name: user.name
}
end
end
Example response Carve will render for this view:
{
"result": {
"id": "D3Wcorr0oa",
"type": "user",
"data": {
"id": "D3Wcorr0oa",
"name": "John Doe",
"team_id": "Xk9Lp2Rr4m",
"profile_id": "Bz7Jt5Yq1n"
}
},
"links": [
{
"id": "Xk9Lp2Rr4m",
"type": "team",
"data": {
"id": "Xk9Lp2Rr4m",
"name": "Engineering Team",
"description": "Our awesome engineering team"
}
},
{
"id": "Bz7Jt5Yq1n",
"type": "profile",
"data": {
"id": "Bz7Jt5Yq1n",
"bio": "Software engineer passionate about Elixir",
"avatar_url": "https://example.com/avatars/johndoe.jpg"
}
}
]
}
How does it work?
- Carve macros create view functions
index(%{ result: users })
andshow(%{ result: user })
- Controller calls these view functions
- Carve pulls the list of links for given data (list or single record)
- Carve calls the
get_by_id
(get
macro expanded) andprepare_for_view
(view
macro expanded) functions for each link - The final expanded list of links get flattened & cleaned, returned to user with the main result:
{ result: {} || [], links: [] }