Packages
A serialization library implementing the jsonapi.org 1.0 spec suitable for use building JSON APIs in Phoenix and any other Plug based framework or app.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/ja_serializer.gen.phoenix_api.ex
if Code.ensure_loaded?(Phoenix) do
defmodule Mix.Tasks.JaSerializer.Gen.PhoenixApi do
use Mix.Task
@shortdoc "Generates a controller and model for a JSON API based resource"
@moduledoc """
Generates a Phoenix resource.
mix phoenix.gen.json_api User users name:string age:integer
The first argument is the module name followed by
its plural name (used for resources and schema).
The generated resource will contain:
* a model in web/models
* a view in web/views
* a controller in web/controllers
* a migration file for the repository
* test files for generated model and controller
If you already have a model, the generated model can be skipped
with `--no-model`. Read the documentation for `phoenix.gen.model`
for more information on attributes and namespaced resources.
"""
def run(args) do
switches = [binary_id: :boolean, model: :boolean]
{opts, parsed, _} = OptionParser.parse(args, switches: switches)
[singular, plural | attrs] = validate_args!(parsed)
default_opts = Application.get_env(:phoenix, :generators, [])
opts = Keyword.merge(default_opts, opts)
attrs = Mix.Phoenix.attrs(attrs)
refs = references(attrs)
non_refs = non_references(attrs) ++ [:inserted_at, :updated_at] |> Enum.map(fn(x) -> Atom.to_string(x) end)
binding = Mix.Phoenix.inflect(singular)
path = binding[:path]
route = String.split(path, "/") |> Enum.drop(-1) |> Kernel.++([plural]) |> Enum.join("/")
binding = binding ++ [plural: plural, route: route,
binary_id: opts[:binary_id],
attrs: attrs, params: Mix.Phoenix.params(attrs),
refs: refs, non_refs: non_refs]
Mix.Phoenix.check_module_name_availability!(binding[:module] <> "Controller")
Mix.Phoenix.check_module_name_availability!(binding[:module] <> "View")
files = [
{:eex, "controller.ex", "web/controllers/#{path}_controller.ex"},
{:eex, "view.ex", "web/views/#{path}_view.ex"},
{:eex, "controller_test.exs", "test/controllers/#{path}_controller_test.exs"},
]
unless File.exists?("web/views/changeset_view.ex") do
Mix.Phoenix.copy_from paths(), "deps/phoenix/priv/templates/phoenix.gen.json", "", binding, [{:eex, "changeset_view.ex", "web/views/changeset_view.ex"}]
end
if File.exists?("priv/templates/ja_serializer.gen.phoenix_api/") do
Mix.Phoenix.copy_from paths(), "priv/templates/ja_serializer.gen.phoenix_api", "", binding, files
else
Mix.Phoenix.copy_from paths(), "deps/ja_serializer/priv/templates/ja_serializer.gen.phoenix_api", "", binding, files
end
instructions = compile_instructions(route, binding, refs)
if opts[:model] != false do
Mix.Task.run "phoenix.gen.model", ["--instructions", instructions|args]
else
Mix.shell.info instructions
end
end
defp compile_instructions(route, binding, []) do
"""
Add the resource to your api scope in web/router.ex:
resources "/#{route}", #{binding[:scoped]}Controller, except: [:new, :edit]
"""
end
defp compile_instructions(route, binding, refs) do
compile_instructions(route, binding, []) <> """
Add
+ scoped resource in web/router.ex
+ has_many associations in web/models
+ has_many associations in web/views
For:
#{inspect(Enum.map(refs, &(&1 <> "s")))}
"""
end
defp validate_args!([_, plural | _] = args) do
cond do
String.contains?(plural, ":") ->
raise_with_help
plural != Phoenix.Naming.underscore(plural) ->
Mix.raise "expected the second argument, #{inspect plural}, to be all lowercase using snake_case convention"
true ->
args
end
end
defp validate_args!(_) do
raise_with_help
end
defp raise_with_help do
Mix.raise """
mix phoenix.gen.json_api expects both singular and plural names
of the generated resource followed by any number of attributes:
mix phoenix.gen.json_api User users name:string
"""
end
defp paths do
[".", :phoenix]
end
defp references(attrs) do
rv = for {k, v} <- attrs do
references_strings({k, v})
end
rv |> Enum.reject(fn(x) -> is_nil(x) end)
end
defp references_strings({k, v}) when is_tuple(v), do: Atom.to_string(k) |> String.replace_trailing("_id", "")
defp references_strings(_), do: nil
defp non_references(attrs) do
rv = for {k, v} <- attrs do
non_references_strings({k, v})
end
rv |> Enum.reject(fn(x) -> is_nil(x) end)
end
defp non_references_strings({_k, v}) when is_tuple(v), do: nil
defp non_references_strings({k, _v}), do: k
end
end