Page MenuHomePhorge

No OneTemporary

Size
18 KB
Referenced Files
None
Subscribers
None
diff --git a/.gitignore b/.gitignore
index 12179ea..c2d0238 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,20 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
+
+# IDE / plugin files
+.elixir_ls/
+.vscode/
diff --git a/examples/phoenix_app/README.md b/examples/phoenix_app/README.md
index b351da7..7e182ce 100644
--- a/examples/phoenix_app/README.md
+++ b/examples/phoenix_app/README.md
@@ -1,7 +1,19 @@
# PhoenixApp
This simple Phoenix API Application demonstrates the usage of `open_api_spex`.
- [api_spec.ex](lib/phoenix_app_web/api_spec.ex) contains the outline of the api spec
- [schemas.ex](lib/phoenix_app_web/schemas.ex) conains the request/response schema modules
- - [router.ex][lib/phoenix_app_web/router.ex]
\ No newline at end of file
+ - [router.ex](lib/phoenix_app_web/router.ex)
+
+
+To run this application:
+
+ ```
+ mix deps.get
+ mix ecto.create
+ mix ecto.migrate
+ mix phx.server
+ ```
+
+ Navigate to [http://localhost:4000/swaggerui](http://localhost:4000/swaggerui)
\ No newline at end of file
diff --git a/.gitignore b/examples/plug_app/.gitignore
similarity index 100%
copy from .gitignore
copy to examples/plug_app/.gitignore
diff --git a/examples/plug_app/README.md b/examples/plug_app/README.md
new file mode 100644
index 0000000..964a41d
--- /dev/null
+++ b/examples/plug_app/README.md
@@ -0,0 +1,18 @@
+# PlugApp
+
+This simple Plug API Application demonstrates the usage of `open_api_spex`.
+
+ - [api_spec.ex](lib/plug_app/api_spec.ex) contains the outline of the api spec
+ - [schemas.ex](lib/plug_app/schemas.ex) conains the request/response schema modules
+ - [router.ex](lib/plug_app/router.ex) contains the plug router
+
+ To run this application:
+
+ ```
+ mix deps.get
+ mix ecto.create
+ mix ecto.migrate
+ mix run --no-halt
+ ```
+
+ Navigate to [http://localhost:4000/swaggerui](http://localhost:4000/swaggerui)
\ No newline at end of file
diff --git a/examples/plug_app/config/config.exs b/examples/plug_app/config/config.exs
new file mode 100644
index 0000000..a1eb420
--- /dev/null
+++ b/examples/plug_app/config/config.exs
@@ -0,0 +1,12 @@
+# This file is responsible for configuring your application
+# and its dependencies with the aid of the Mix.Config module.
+use Mix.Config
+
+config :plug_app, ecto_repos: [PlugApp.Repo]
+
+config :plug_app, PlugApp.Repo,
+ adapter: Sqlite.Ecto2,
+ database: "priv/repo/plug_app.db"
+
+config :logger, level: :debug
+
diff --git a/examples/plug_app/lib/plug_app/accounts/accounts.ex b/examples/plug_app/lib/plug_app/accounts/accounts.ex
new file mode 100644
index 0000000..7aedeba
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/accounts/accounts.ex
@@ -0,0 +1,17 @@
+defmodule PlugApp.Accounts do
+ alias PlugApp.Accounts.User
+ alias PlugApp.Repo
+
+ def list_users() do
+ Repo.all(User)
+ end
+
+ def get_user!(id) do
+ Repo.get(User, id)
+ end
+
+ def create_user(%{name: name, email: email}) do
+ user = Repo.insert!(%User{name: name, email: email})
+ {:ok, user}
+ end
+end
diff --git a/examples/plug_app/lib/plug_app/accounts/user.ex b/examples/plug_app/lib/plug_app/accounts/user.ex
new file mode 100644
index 0000000..ca4becf
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/accounts/user.ex
@@ -0,0 +1,9 @@
+defmodule PlugApp.Accounts.User do
+ use Ecto.Schema
+
+ schema "users" do
+ field :name, :string
+ field :email, :string
+ timestamps()
+ end
+end
diff --git a/examples/plug_app/lib/plug_app/api_spec.ex b/examples/plug_app/lib/plug_app/api_spec.ex
new file mode 100644
index 0000000..e0ca006
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/api_spec.ex
@@ -0,0 +1,22 @@
+defmodule PlugApp.ApiSpec do
+ alias OpenApiSpex.{Info, OpenApi, Paths}
+
+ def spec do
+ %OpenApi{
+ info: %Info{
+ title: "Plug App",
+ version: "1.0"
+ },
+ paths: %{
+ "/api/users/{id}" => OpenApiSpex.PathItem.from_routes([
+ %{verb: :get, plug: PlugApp.UserHandler.Show, opts: []}
+ ]),
+ "/api/users" => OpenApiSpex.PathItem.from_routes([
+ %{verb: :get, plug: PlugApp.UserHandler.Index, opts: []},
+ %{verb: :post, plug: PlugApp.UserHandler.Create, opts: []}
+ ])
+ }
+ }
+ |> OpenApiSpex.resolve_schema_modules()
+ end
+end
\ No newline at end of file
diff --git a/examples/plug_app/lib/plug_app/application.ex b/examples/plug_app/lib/plug_app/application.ex
new file mode 100644
index 0000000..33a7bdd
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/application.ex
@@ -0,0 +1,20 @@
+defmodule PlugApp.Application do
+ # See https://hexdocs.pm/elixir/Application.html
+ # for more information on OTP Applications
+ @moduledoc false
+
+ use Application
+
+ def start(_type, _args) do
+ # List all child processes to be supervised
+ children = [
+ PlugApp.Repo,
+ Plug.Adapters.Cowboy.child_spec(:http, PlugApp.Router, [], [port: 4000])
+ ]
+
+ # See https://hexdocs.pm/elixir/Supervisor.html
+ # for other strategies and supported options
+ opts = [strategy: :one_for_one, name: PlugApp.Supervisor]
+ Supervisor.start_link(children, opts)
+ end
+end
diff --git a/examples/plug_app/lib/plug_app/repo.ex b/examples/plug_app/lib/plug_app/repo.ex
new file mode 100644
index 0000000..2a7eac6
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/repo.ex
@@ -0,0 +1,3 @@
+defmodule PlugApp.Repo do
+ use Ecto.Repo, otp_app: :plug_app, adapter: Sqlite.Ecto2
+end
\ No newline at end of file
diff --git a/examples/plug_app/lib/plug_app/router.ex b/examples/plug_app/lib/plug_app/router.ex
new file mode 100644
index 0000000..d765f71
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/router.ex
@@ -0,0 +1,35 @@
+defmodule PlugApp.Router.Html do
+ use Plug.Router
+
+ plug :match
+ plug :dispatch
+
+ get "/swaggerui", to: OpenApiSpex.Plug.SwaggerUI, init_opts: [path: "/api/openapi"]
+end
+
+defmodule PlugApp.Router.Api do
+ use Plug.Router
+
+ plug OpenApiSpex.Plug.PutApiSpec, module: PlugApp.ApiSpec
+ plug :match
+ plug :dispatch
+
+ get "/api/users", to: PlugApp.UserHandler.Index
+ post "/api/users", to: PlugApp.UserHandler.Create
+ get "/api/users/:id", to: PlugApp.UserHandler.Show
+ get "/api/openapi", to: OpenApiSpex.Plug.RenderSpec
+end
+
+defmodule PlugApp.Router do
+ use Plug.Router
+
+ plug Plug.RequestId
+ plug Plug.Logger
+ plug Plug.Parsers, parsers: [:json], pass: ["*/*"], json_decoder: Poison
+ plug :match
+ plug :dispatch
+
+ match "/api/*_", to: PlugApp.Router.Api
+ match "/*_", to: PlugApp.Router.Html
+end
+
diff --git a/examples/plug_app/lib/plug_app/schemas.ex b/examples/plug_app/lib/plug_app/schemas.ex
new file mode 100644
index 0000000..e803d07
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/schemas.ex
@@ -0,0 +1,91 @@
+defmodule PlugApp.Schemas do
+ require OpenApiSpex
+ alias OpenApiSpex.Schema
+
+ defmodule User do
+ OpenApiSpex.schema %{
+ title: "User",
+ description: "A user of the app",
+ type: :object,
+ properties: %{
+ id: %Schema{type: :integer, description: "User ID"},
+ name: %Schema{type: :string, description: "User name", pattern: ~r/[a-zA-Z][a-zA-Z0-9_]+/},
+ email: %Schema{type: :string, description: "Email address", format: :email},
+ inserted_at: %Schema{type: :string, description: "Creation timestamp", format: :'date-time'},
+ updated_at: %Schema{type: :string, description: "Update timestamp", format: :'date-time'}
+ },
+ required: [:name, :email],
+ example: %{
+ "id" => 123,
+ "name" => "Joe User",
+ "email" => "joe@gmail.com",
+ "inserted_at" => "2017-09-12T12:34:55Z",
+ "updated_at" => "2017-09-13T10:11:12Z"
+ }
+ }
+ end
+
+ defmodule UserRequest do
+ OpenApiSpex.schema %{
+ title: "UserRequest",
+ description: "POST body for creating a user",
+ type: :object,
+ properties: %{
+ user: User
+ },
+ required: [:user],
+ example: %{
+ "user" => %{
+ "name" => "Joe User",
+ "email" => "joe@gmail.com"
+ }
+ }
+ }
+ end
+
+ defmodule UserResponse do
+ OpenApiSpex.schema %{
+ title: "UserResponse",
+ description: "Response schema for single user",
+ type: :object,
+ properties: %{
+ data: User
+ },
+ example: %{
+ "data" => %{
+ "id" => 123,
+ "name" => "Joe User",
+ "email" => "joe@gmail.com",
+ "inserted_at" => "2017-09-12T12:34:55Z",
+ "updated_at" => "2017-09-13T10:11:12Z"
+ }
+ },
+ "x-struct": __MODULE__
+ }
+ end
+
+ defmodule UsersResponse do
+ OpenApiSpex.schema %{
+ title: "UsersResponse",
+ description: "Response schema for multiple users",
+ type: :object,
+ properties: %{
+ data: %Schema{description: "The users details", type: :array, items: User}
+ },
+ example: %{
+ "data" => [
+ %{
+ "id" => 123,
+ "name" => "Joe User",
+ "email" => "joe@gmail.com"
+ },
+ %{
+ "id" => 456,
+ "name" => "Jay Consumer",
+ "email" => "jay@yahoo.com"
+ }
+ ]
+ }
+ }
+ end
+end
\ No newline at end of file
diff --git a/examples/plug_app/lib/plug_app/user_handler.ex b/examples/plug_app/lib/plug_app/user_handler.ex
new file mode 100644
index 0000000..6a2761f
--- /dev/null
+++ b/examples/plug_app/lib/plug_app/user_handler.ex
@@ -0,0 +1,117 @@
+defmodule PlugApp.UserHandler do
+ alias OpenApiSpex.Operation
+ alias PlugApp.{Accounts, Accounts.User}
+ alias PlugApp.Schemas
+ import OpenApiSpex.Operation, only: [parameter: 5, request_body: 4, response: 3]
+
+ defmodule Index do
+ use Plug.Builder
+
+ plug OpenApiSpex.Plug.Cast, operation_id: "UserHandler.Index"
+ plug OpenApiSpex.Plug.Validate
+ plug :index
+
+ def open_api_operation(_) do
+ %Operation{
+ tags: ["users"],
+ summary: "List users",
+ description: "List all useres",
+ operationId: "UserHandler.Index",
+ responses: %{
+ 200 => response("User List Response", "application/json", Schemas.UsersResponse)
+ }
+ }
+ end
+
+ def index(conn, _opts) do
+ users = Accounts.list_users()
+ conn
+ |> Plug.Conn.put_resp_header("Content-Type", "application/json")
+ |> Plug.Conn.send_resp(200, render(users))
+ end
+
+ def render(users) do
+ %{
+ data: Enum.map(users, &Map.take(&1, [:id, :name, :email]))
+ }
+ |> Poison.encode!(pretty: true)
+ end
+ end
+
+ defmodule Show do
+ use Plug.Builder
+
+ plug OpenApiSpex.Plug.Cast, operation_id: "UserHandler.Show"
+ plug OpenApiSpex.Plug.Validate
+ plug :load
+ plug :show
+
+ def open_api_operation(_) do
+ %Operation{
+ tags: ["users"],
+ summary: "Show user",
+ description: "Show a user by ID",
+ operationId: "UserHandler.Show",
+ parameters: [
+ parameter(:id, :path, :integer, "User ID", example: 123, minimum: 1)
+ ],
+ responses: %{
+ 200 => response("User", "application/json", Schemas.UserResponse)
+ }
+ }
+ end
+
+ def load(conn = %Plug.Conn{params: %{id: id}}, _opts) do
+ case Accounts.get_user!(id) do
+ nil ->
+ conn
+ |> put_resp_header("Content-Type", "application/json")
+ |> send_resp(404, ~s({"error": "User not found"}))
+ |> halt()
+
+ user -> assign(conn, :user, user)
+ end
+ end
+
+ def show(conn = %Plug.Conn{assigns: %{user: user}}, _opts) do
+ conn
+ |> put_resp_header("Content-Type", "application/json")
+ |> send_resp(200, render(user))
+ end
+
+ def render(user) do
+ %{
+ data: Map.take(user, [:id, :name, :email])
+ }
+ |> Poison.encode!(pretty: true)
+ end
+ end
+
+ defmodule Create do
+ use Plug.Builder
+
+ plug OpenApiSpex.Plug.Cast, operation_id: "UserHandler.Create"
+ plug OpenApiSpex.Plug.Validate
+ plug :create
+
+ def open_api_operation(_) do
+ %Operation{
+ tags: ["users"],
+ summary: "Create user",
+ description: "Create a user",
+ operationId: "UserHandler.Create",
+ requestBody: request_body("The user attributes", "application/json", Schemas.UserRequest, required: true),
+ responses: %{
+ 201 => response("User", "application/json", Schemas.UserResponse)
+ }
+ }
+ end
+
+ def create(conn = %Plug.Conn{params: %Schemas.UserRequest{user: user_params}}, _opts) do
+ with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
+ conn
+ |> Plug.Conn.send_resp(201, Show.render(user))
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/examples/plug_app/mix.exs b/examples/plug_app/mix.exs
new file mode 100644
index 0000000..8ceaab1
--- /dev/null
+++ b/examples/plug_app/mix.exs
@@ -0,0 +1,34 @@
+defmodule PlugApp.Mixfile do
+ use Mix.Project
+
+ def project do
+ [
+ app: :plug_app,
+ version: "0.1.0",
+ elixir: "~> 1.5",
+ start_permanent: Mix.env == :prod,
+ deps: deps()
+ ]
+ end
+
+ # Run "mix help compile.app" to learn about applications.
+ def application do
+ [
+ extra_applications: [:logger],
+ mod: {PlugApp.Application, []}
+ ]
+ end
+
+ # Run "mix help deps" to learn about dependencies.
+ defp deps do
+ [
+ {:open_api_spex, path: "../../"},
+ {:cowboy, "~> 1.0"},
+ {:plug, "~> 1.0"},
+ {:ecto, "~> 2.2"},
+ {:sqlite_ecto2, "~> 2.2"}
+ # {:dep_from_hexpm, "~> 0.3.0"},
+ # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
+ ]
+ end
+end
diff --git a/examples/plug_app/mix.lock b/examples/plug_app/mix.lock
new file mode 100644
index 0000000..b5d3270
--- /dev/null
+++ b/examples/plug_app/mix.lock
@@ -0,0 +1,15 @@
+%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [], [], "hexpm"},
+ "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
+ "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [], [], "hexpm"},
+ "db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
+ "decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [], [], "hexpm"},
+ "ecto": {:hex, :ecto, "2.2.6", "3fd1067661d6d64851a0d4db9acd9e884c00d2d1aa41cc09da687226cf894661", [], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
+ "esqlite": {:hex, :esqlite, "0.2.3", "1a8b60877fdd3d50a8a84b342db04032c0231cc27ecff4ddd0d934485d4c0cd5", [], [], "hexpm"},
+ "mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [], [], "hexpm"},
+ "plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
+ "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"},
+ "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [], [], "hexpm"},
+ "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [], [], "hexpm"},
+ "sbroker": {:hex, :sbroker, "1.0.0", "28ff1b5e58887c5098539f236307b36fe1d3edaa2acff9d6a3d17c2dcafebbd0", [], [], "hexpm"},
+ "sqlite_ecto2": {:hex, :sqlite_ecto2, "2.2.2", "7a3e5c0521e1cb6e30a4907ba4d952b97db9b2ab5d1a4806ceeb66a10b23ba65", [], [{:connection, "~> 1.0.3", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 2.2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.3", [hex: :esqlite, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: false]}, {:sqlitex, "~> 1.3.2 or ~> 1.4", [hex: :sqlitex, repo: "hexpm", optional: false]}], "hexpm"},
+ "sqlitex": {:hex, :sqlitex, "1.3.3", "3aac5fd702be346f71d9de6e01702c9954484cd0971aa443490bb3bde045d919", [], [{:decimal, "~> 1.1", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.3", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"}}
diff --git a/examples/plug_app/priv/repo/migrations/20171015110840_add_users.exs b/examples/plug_app/priv/repo/migrations/20171015110840_add_users.exs
new file mode 100644
index 0000000..8af3749
--- /dev/null
+++ b/examples/plug_app/priv/repo/migrations/20171015110840_add_users.exs
@@ -0,0 +1,11 @@
+defmodule PlugApp.Repo.Migrations.AddUsers do
+ use Ecto.Migration
+
+ def change do
+ create table(:users) do
+ add :name, :string, null: false
+ add :email, :string, null: false
+ timestamps()
+ end
+ end
+end
diff --git a/examples/plug_app/test/test_helper.exs b/examples/plug_app/test/test_helper.exs
new file mode 100644
index 0000000..869559e
--- /dev/null
+++ b/examples/plug_app/test/test_helper.exs
@@ -0,0 +1 @@
+ExUnit.start()

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 10:57 AM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38947
Default Alt Text
(18 KB)

Event Timeline