Proof of concept Json-API with OpenAPI support

Using AshJsonApi.OpenApi helpers to generate OpenAPI
This commit is contained in:
Mike Buhot 2022-11-21 17:47:48 +10:00 committed by Zach Daniel
parent cf8b5f356b
commit 452193335d
8 changed files with 124 additions and 12 deletions

View file

@ -90,6 +90,11 @@ config :plug_content_security_policy,
worker_src: ~w('self')
}
# Mime type for JSON:API routes
config :mime, :types, %{
"application/vnd.api+json" => ["json"]
}
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"

View file

@ -5,6 +5,7 @@ defmodule AshHq.Docs do
use Ash.Api,
extensions: [
AshGraphql.Api,
AshJsonApi.Api,
AshAdmin.Api
]
@ -20,4 +21,11 @@ defmodule AshHq.Docs do
resources do
registry AshHq.Docs.Registry
end
json_api do
prefix "/json_api"
serve_schema? true
open_api {AshHq.Docs.OpenApi, :spec, []}
log_errors? true
end
end

View file

@ -0,0 +1,35 @@
defmodule AshHq.Docs.OpenApi do
alias OpenApiSpex.{Info, OpenApi, Server, SecurityScheme}
def spec do
%OpenApi{
info: %Info{
title: "AshHQ Docs API",
version: "1.1"
},
servers: [
Server.from_endpoint(AshHqWeb.Endpoint)
],
paths: AshJsonApi.OpenApi.paths(AshHq.Docs),
tags: AshJsonApi.OpenApi.tags(AshHq.Docs),
components: %{
responses: AshJsonApi.OpenApi.responses(),
schemas: AshJsonApi.OpenApi.schemas(AshHq.Docs),
securitySchemes: %{
"api_key" => %SecurityScheme{
type: "apiKey",
description: "API Key provided in the Authorization header",
name: "api_key",
in: "header"
}
}
},
security: [
%{
# API Key security applies to all operations
"api_key" => []
}
]
}
end
end

View file

@ -6,9 +6,23 @@ defmodule AshHq.Docs.Guide do
AshHq.Docs.Extensions.Search,
AshHq.Docs.Extensions.RenderMarkdown,
AshGraphql.Resource,
AshJsonApi.Resource,
AshAdmin.Resource
]
json_api do
type "guide"
includes [library_version: [:library]]
routes do
base "/guides"
get :read
index :read
index :read_for_version, route: "/for-version"
end
end
attributes do
uuid_primary_key :id

View file

@ -0,0 +1,15 @@
defmodule AshHqWeb.DocsJsonApiRouter do
use AshJsonApi.Api.Router, api: AshHq.Docs, registry: AshHq.Docs.Registry
get "/swaggerui",
to: OpenApiSpex.Plug.SwaggerUI,
init_opts: [
path: "/json_api/openapi",
title: "AshHQ JSON-API - Swagger UI",
default_model_expand_depth: 4
]
get "/redoc",
to: Redoc.Plug.RedocUI,
init_opts: [spec_url: "/json_api/openapi"]
end

View file

@ -83,6 +83,7 @@ defmodule AshHqWeb.Router do
## Api routes
scope "/" do
forward("/json_api", AshHqWeb.DocsJsonApiRouter)
forward("/gql", Absinthe.Plug, schema: AshHqWeb.Schema)
forward(
@ -93,6 +94,34 @@ defmodule AshHqWeb.Router do
)
end
## Authentication routes
scope "/", AshHqWeb do
pipe_through([
:browser,
:dead_view_authentication,
:redirect_if_user_is_authenticated,
:put_session_layout
])
get("/users/new_session", UserSessionController, :log_in)
post("/users/new_session", UserSessionController, :log_in)
end
scope "/", AshHqWeb do
pipe_through([:browser, :dead_view_authentication, :require_authenticated_user])
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
end
scope "/", AshHqWeb do
pipe_through([:browser, :dead_view_authentication])
post("/users/log_out", UserSessionController, :delete)
post("/users/confirm", UserConfirmationController, :create)
get("/users/confirm/:token", UserConfirmationController, :confirm)
end
# Enables LiveDashboard only for development
#
# If you want to use the LiveDashboard in production, you should put

View file

@ -47,6 +47,7 @@ defmodule AshHq.MixProject do
{:ash_json_api, github: "ash-project/ash_json_api"},
{:ash_authentication, github: "team-alembic/ash_authentication", override: true},
{:ash_authentication_phoenix, github: "team-alembic/ash_authentication_phoenix"},
{:absinthe_plug, "~> 1.5"},
{:ash_blog, github: "ash-project/ash_blog"},
{:ash_csv, github: "ash-project/ash_csv"},
# Discord
@ -85,6 +86,9 @@ defmodule AshHq.MixProject do
{:phoenix_live_dashboard, "~> 0.6"},
{:ecto_psql_extras, "~> 0.6"},
{:phoenix_ecto, "~> 4.4"},
# OpenApiSpex / SwaggerUI / Redoc
{:open_api_spex, "~> 3.16"},
{:redoc_ui_plug, github: "team-alembic/redoc_ui_plug"},
# Phoenix/Core dependencies
{:phoenix, "~> 1.7.0-rc.1", override: true},
{:phoenix_view, "~> 2.0"},

View file

@ -1,17 +1,17 @@
%{
"absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"},
"absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"},
"ash": {:git, "https://github.com/ash-project/ash.git", "4e0917e36882942b045a2ecc6caef8360dd1fd73", []},
"ash_admin": {:git, "https://github.com/ash-project/ash_admin.git", "3002af9ec69dc475582ef5f445064e4594bf45ac", []},
"ash_authentication": {:git, "https://github.com/team-alembic/ash_authentication.git", "2bca91cce4396e51643b28b1b6bb63cc9812085d", []},
"ash_authentication_phoenix": {:git, "https://github.com/team-alembic/ash_authentication_phoenix.git", "ee73b067cbbf4c018e5f218e632cc60f3c69c316", []},
"ash_blog": {:git, "https://github.com/ash-project/ash_blog.git", "9254773dfedabfc7987af6326a62885c24c3655b", []},
"ash_csv": {:git, "https://github.com/ash-project/ash_csv.git", "7f47b820077619ccb7340fbede0c4fd1b5313a17", []},
"ash_graphql": {:git, "https://github.com/ash-project/ash_graphql.git", "2a9baf81646f242c1c17f2d28a381e4e02bea21e", []},
"ash_json_api": {:git, "https://github.com/ash-project/ash_json_api.git", "9663ddc68ec2384cc3412a997eacdb6e3f4c29d8", []},
"ash_phoenix": {:git, "https://github.com/ash-project/ash_phoenix.git", "35e4d2931e1664383c9a085a90f846e58986c8c8", []},
"ash_postgres": {:git, "https://github.com/ash-project/ash_postgres.git", "c70fffba584b93acd5bfe1ecfd0baf87fb21f887", []},
"assent": {:hex, :assent, "0.2.1", "46ad0ed92b72330f38c60bc03c528e8408475dc386f48d4ecd18833cfa581b9f", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: true]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "58c558b6029ffa287e15b38c8e07cd99f0b24e4846c52abad0c0a6225c4873bc"},
"ash": {:git, "https://github.com/ash-project/ash.git", "a31da97d4ce1fa396e35e25f0c4d6f1eeb51a05a", []},
"ash_admin": {:git, "https://github.com/ash-project/ash_admin.git", "5dfb19785c587d56f6443e99b6f976cf6c2c92c8", []},
"ash_authentication": {:git, "https://github.com/team-alembic/ash_authentication.git", "a7c296f21ad8a88e3643ef1b8eefea93aea3c41d", []},
"ash_authentication_phoenix": {:git, "https://github.com/team-alembic/ash_authentication_phoenix.git", "36c7af946e61772d1803211f18156bc1158092e8", []},
"ash_blog": {:git, "https://github.com/ash-project/ash_blog.git", "79d1b9077b2712d4d4651eaa36c8e63119efd565", []},
"ash_csv": {:git, "https://github.com/ash-project/ash_csv.git", "bad0f6961bf5d135450dacda687d9df0549e80ae", []},
"ash_graphql": {:git, "https://github.com/ash-project/ash_graphql.git", "fb7b60f9e1793c912e238043aa115cd6585c19b7", []},
"ash_json_api": {:git, "https://github.com/ash-project/ash_json_api.git", "eb183ba3cdb511e05270d3906a4ca5a70e5d59d9", []},
"ash_phoenix": {:git, "https://github.com/ash-project/ash_phoenix.git", "5ffcd1916ece639c684273e632cc0aecebe82f26", []},
"ash_postgres": {:git, "https://github.com/ash-project/ash_postgres.git", "124e29c1add14c23b05344f2dfc526dcbbfed70d", []},
"assent": {:hex, :assent, "0.2.3", "414d77ea27349dacc980b612e9edeed06c4d64a3df99a0fa8e42e6940ed20c16", [:mix], [{:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: true]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "a39bc5b57920632b003bd175fd58fcb355c10efbe614bba03682ce2a76d4133f"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.0.1", "9be815469e6bfefec40fa74658ecbbe6897acfb57614df1416eeccd4903f602c", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "486bb95efb645d1efc6794c1ddd776a186a9a713abf06f45708a6ce324fb96cf"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
@ -34,7 +34,7 @@
"dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"},
"earmark": {:hex, :earmark, "1.5.0-pre1", "e04aca73692bc3cda3429d6df99c8dae2bf76411e5e76d006a4bc04ac81ef1c1", [:mix], [{:earmark_parser, "~> 1.4.21", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "26ec0473ad2ef995b9672f89309a7a4952887f69b78cfc7af14e320bc6546bfa"},
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
"ecto": {:hex, :ecto, "3.9.5", "9f0aa7ae44a1577b651c98791c6988cd1b69b21bc724e3fd67090b97f7604263", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4f3115d8cbacdc0bfa4b742865459fb1371d0715515842a1fb17fe31920b74c"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
"ed25519": {:hex, :ed25519, "1.4.1", "479fb83c3e31987c9cad780e6aeb8f2015fb5a482618cdf2a825c9aff809afc4", [:mix], [], "hexpm", "0dacb84f3faa3d8148e81019ca35f9d8dcee13232c32c9db5c2fb8ff48c80ec7"},
@ -81,6 +81,7 @@
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nostrum": {:git, "https://github.com/zachdaniel/nostrum.git", "00110f97fb2a9534cf506bca01b79fd092b32581", []},
"open_api_spex": {:hex, :open_api_spex, "3.16.0", "9843af4e87550cd8ac5821b10e4c74f1d51f0d4e3310f824d780614743423b25", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "bb0be24a648b73e8fc8cbda17f514b8486262275e8b33e8b5ae66283df972129"},
"parallel_stream": {:hex, :parallel_stream, "1.1.0", "f52f73eb344bc22de335992377413138405796e0d0ad99d995d9977ac29f1ca9", [:mix], [], "hexpm", "684fd19191aedfaf387bbabbeb8ff3c752f0220c8112eb907d797f4592d6e871"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.7.0-rc.2", "8faaff6f699aad2fe6a003c627da65d0864c868a4c10973ff90abfd7286c1f27", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "71abde2f67330c55b625dcc0e42bf76662dbadc7553c4f545c2f3759f40f7487"},
@ -101,6 +102,7 @@
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"premailex": {:hex, :premailex, "0.3.16", "25c0c9c969f0025bbfdb06834f8f0fbd46e5ec50f5c252e6492165802ffbd2a6", [:mix], [{:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:floki, "~> 0.19", [hex: :floki, repo: "hexpm", optional: false]}, {:meeseeks, "~> 0.11", [hex: :meeseeks, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "c6b042f89ca63025dfbe3ef54fdbbe9d5f043b7c33d8e58f43a41d13a9475111"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"redoc_ui_plug": {:git, "https://github.com/team-alembic/redoc_ui_plug.git", "19d2b85f6ae122e08fdf37b7b2c1cd170ac846c8", []},
"salsa20": {:hex, :salsa20, "1.0.4", "404cbea1fa8e68a41bcc834c0a2571ac175580fec01cc38cc70c0fb9ffc87e9b", [:mix], [], "hexpm", "745ddcd8cfa563ddb0fd61e7ce48d5146279a2cf7834e1da8441b369fdc58ac6"},
"slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"},
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},