Packages
ash_json_api
1.6.0-rc.2
1.7.1
1.7.0
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0-rc.2
1.6.0-rc.1
1.6.0-rc.0
1.5.1
1.5.0
1.4.45
1.4.44
1.4.43
1.4.42
1.4.41
1.4.40
1.4.39
1.4.38
1.4.37
1.4.36
1.4.35
1.4.34
1.4.33
1.4.32
1.4.31
1.4.30
1.4.29
1.4.28
1.4.27
1.4.26
1.4.25
1.4.24
1.4.23
1.4.22
1.4.21
1.4.20
1.4.19
1.4.18
1.4.17
1.4.16
1.4.15
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.8
1.3.7
1.3.6
1.3.5
1.3.4
retired
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-rc.6
1.0.0-rc.5
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.34.2
0.34.1
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.3
0.31.2
retired
0.31.1
0.31.0
0.30.1
0.30.0-rc.4
0.30.0-rc.3
0.30.0-rc.2
0.30.0-rc.1
0.30.0-rc.0
0.29.1
0.29.0
0.28.6
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.6
0.27.5
0.27.1
0.27.0
0.25.0
0.24.4
0.24.2
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.1
0.10.0
0.9.0
0.8.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.4
0.2.3
0.2.1
0.2.0
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
The JSON:API extension for the Ash Framework.
Current section
Files
Jump to
Current section
Files
lib/ash_json_api/igniter.ex
# SPDX-FileCopyrightText: 2019 ash_json_api contributors <https://github.com/ash-project/ash_json_api/graphs/contributors>
#
# SPDX-License-Identifier: MIT
if Code.ensure_loaded?(Igniter) do
defmodule AshJsonApi.Igniter do
@moduledoc "Codemods and utilities for working with AshJsonApi & Igniter"
@doc "Returns the AshJsonApi router containing the domain in question, or a list of all AshJsonApi schemas"
def find_ash_json_api_router(igniter, domain) do
{igniter, modules} = ash_json_api_routers(igniter)
modules
|> Enum.find(fn module ->
with {:ok, {_igniter, _source, zipper}} <-
Igniter.Project.Module.find_module(igniter, module),
{:ok, zipper} <- Igniter.Code.Module.move_to_use(zipper, AshJsonApi.Router),
{:ok, zipper} <- Igniter.Code.Function.move_to_nth_argument(zipper, 1),
{:ok, zipper} <- Igniter.Code.Keyword.get_key(zipper, :domains),
{:ok, _zipper} <-
Igniter.Code.List.move_to_list_item(
zipper,
&Igniter.Code.Common.nodes_equal?(&1, domain)
) do
true
else
_ ->
false
end
end)
|> case do
nil ->
{:error, igniter, modules}
module ->
{:ok, igniter, module}
end
end
@doc "Sets up an `AshJsonApi.Router` for AshJsonApi"
def setup_ash_json_api_router(igniter, ash_phoenix_router_name \\ nil) do
ash_phoenix_router_name =
ash_phoenix_router_name ||
Igniter.Libs.Phoenix.web_module_name(igniter, "AshJsonApiRouter")
{igniter, domains} = Ash.Domain.Igniter.list_domains(igniter)
{igniter, domains} =
Enum.reduce(domains, {igniter, []}, fn domain, {igniter, list} ->
case Spark.Igniter.has_extension(
igniter,
domain,
Ash.Domain,
:extensions,
AshJsonApi.Domain
) do
{igniter, true} -> {igniter, [domain | list]}
{igniter, false} -> {igniter, list}
end
end)
igniter
|> Igniter.Project.Module.find_and_update_or_create_module(
ash_phoenix_router_name,
"""
use AshJsonApi.Router,
domains: #{inspect(domains)},
open_api: "/open_api"
""",
fn zipper ->
# Should never get here
{:ok, zipper}
end
)
end
@doc "Sets up the phoenix module for AshJsonApi"
def setup_phoenix(igniter, ash_phoenix_router_name \\ nil) do
ash_phoenix_router_name =
ash_phoenix_router_name ||
Igniter.Libs.Phoenix.web_module_name(igniter, "AshJsonApiRouter")
case Igniter.Libs.Phoenix.select_router(igniter) do
{igniter, nil} ->
igniter
|> Igniter.add_warning("""
No Phoenix router found, skipping Phoenix installation.
See the Getting Started guide for instructions on installing AshJsonApi with `plug`.
If you have yet to set up Phoenix, you'll have to do that manually and then rerun this installer.
""")
{igniter, router} ->
igniter
|> update_endpoints(router)
|> Igniter.Project.Config.configure(
"config.exs",
:mime,
[:extensions],
%{
"json" => "application/vnd.api+json"
},
updater: fn zipper ->
Igniter.Code.Map.set_map_key(
zipper,
"json",
"application/vnd.api+json",
fn zipper ->
{:ok, zipper}
end
)
end
)
|> Igniter.Project.Config.configure(
"config.exs",
:mime,
[:types],
%{
"application/vnd.api+json" => ["json"]
},
updater: fn zipper ->
Igniter.Code.Map.set_map_key(
zipper,
"application/vnd.api+json",
["json"],
fn zipper ->
zipper =
if Igniter.Code.List.list?(zipper) do
zipper
else
Sourceror.Zipper.replace(zipper, [zipper.node])
end
Igniter.Code.List.prepend_new_to_list(zipper, "json")
end
)
end
)
|> Igniter.Libs.Phoenix.add_pipeline(:api, "plug :accepts, [\"json\"]",
router: router,
warn_on_present?: false
)
|> Igniter.Libs.Phoenix.add_scope(
"/api/json",
"""
pipe_through [:api]
forward "/swaggerui",
OpenApiSpex.Plug.SwaggerUI,
path: "/api/json/open_api",
default_model_expand_depth: 4
forward "/", #{inspect(ash_phoenix_router_name)}
""",
router: router
)
end
end
def setup_routes_alias(igniter) do
# if `Phoenix.Router` is not loaded we don't
# know what version they are using and conservatively
# do not add an alias that will cause an error
if Code.ensure_loaded?(Phoenix.Router) do
# Phoenix >= 1.8 uses the new formatted routes feature and
# so we do not need this alias
if function_exported?(Phoenix.Router, :__formatted_routes__, 1) do
igniter
else
Igniter.Project.TaskAliases.add_alias(
igniter,
"phx.routes",
["phx.routes", "ash_json_api.routes"],
if_exists: {:append, "ash_json_api.routes"}
)
end
else
igniter
end
end
defp update_endpoints(igniter, router) do
{igniter, endpoints_that_need_parser} =
Igniter.Libs.Phoenix.endpoints_for_router(igniter, router)
Enum.reduce(endpoints_that_need_parser, igniter, fn endpoint, igniter ->
Igniter.Project.Module.find_and_update_module!(igniter, endpoint, fn zipper ->
case Igniter.Code.Function.move_to_function_call_in_current_scope(
zipper,
:plug,
2,
&Igniter.Code.Function.argument_equals?(&1, 0, Plug.Parsers)
) do
{:ok, zipper} ->
with {:ok, zipper} <- Igniter.Code.Function.move_to_nth_argument(zipper, 1),
{:ok, zipper} <- Igniter.Code.Keyword.get_key(zipper, :parsers),
{:ok, zipper} <-
Igniter.Code.List.append_new_to_list(zipper, AshJsonApi.Plug.Parser) do
{:ok, zipper}
else
_ ->
{:warning,
"Could not add `AshJsonApi.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
end
:error ->
case parser_location(zipper) do
{:ok, zipper} ->
{:ok,
Igniter.Code.Common.add_code(zipper, """
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json, AshJsonApi.Plug.Parser],
pass: ["*/*"],
json_decoder: Jason
""")}
_ ->
{:warning,
"Could not add `AshJsonApi.Plug.Parser` to parsers in endpoint #{endpoint}. Please make this change manually."}
end
end
end)
end)
end
defp parser_location(zipper) do
with :error <-
Igniter.Code.Function.move_to_function_call_in_current_scope(
zipper,
:plug,
[1, 2],
&Igniter.Code.Function.argument_equals?(&1, 0, Plug.Telemetry)
),
:error <-
Igniter.Code.Function.move_to_function_call_in_current_scope(
zipper,
:plug,
[1, 2]
) do
Igniter.Code.Module.move_to_use(zipper, Phoenix.Endpoint)
:error
end
end
@doc "Returns all modules that `use AshJsonApi.Router`"
def ash_json_api_routers(igniter) do
Igniter.Project.Module.find_all_matching_modules(igniter, fn _name, zipper ->
match?({:ok, _}, Igniter.Code.Module.move_to_use(zipper, AshJsonApi.Router))
end)
end
end
end