Skip to content

Commit

Permalink
Add swaggerui
Browse files Browse the repository at this point in the history
  • Loading branch information
michalwarda committed Feb 26, 2024
1 parent 36b614a commit c0c7419
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 7 deletions.
2 changes: 1 addition & 1 deletion apps/api/.formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
import_deps: [:ecto, :ecto_sql, :phoenix],
import_deps: [:ecto, :ecto_sql, :phoenix, :open_api_spex],
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
Expand Down
2 changes: 2 additions & 0 deletions apps/api/config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,5 @@ config :buildel, :basic_auth, %{username: "michalmichal", password: "rzadzirzadz
config :buildel, :nlm_api_url, "http://localhost:5010"

config :buildel, :page_url, "http://localhost:3000"

config :open_api_spex, :cache_adapter, OpenApiSpex.Plug.NoneCache
20 changes: 20 additions & 0 deletions apps/api/lib/buildel_web/api_spec.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule BuildelWeb.ApiSpec do
alias OpenApiSpex.{Info, OpenApi, Paths, Server}
alias BuildelWeb.{Endpoint, Router}
@behaviour OpenApi

@impl OpenApi
def spec do
%OpenApi{
servers: [
Server.from_endpoint(Endpoint)
],
info: %Info{
title: "Buildel",
version: "1.0"
},
paths: Paths.from_router(Router)
}
|> OpenApiSpex.resolve_schema_modules()
end
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule BuildelWeb.OrganizationController do
use BuildelWeb, :controller
use BuildelWeb.Validator
use OpenApiSpex.ControllerSpecs

import BuildelWeb.UserAuth

Expand All @@ -11,11 +12,38 @@ defmodule BuildelWeb.OrganizationController do
plug(:fetch_current_user)
plug(:require_authenticated_user)

tags ["organization"]

operation :index,
summary: "List organizations",
parameters: [],
request_body: nil,
responses: [
ok: {"organizations", "application/json", BuildelWeb.Schemas.Organizations.IndexResponse},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

def index(conn, _) do
organizations = conn.assigns.current_user |> Organizations.list_user_organizations()
render(conn, :index, organizations: organizations)
end

operation :show,
summary: "Get organization",
parameters: [
id: [in: :path, description: "Organization ID", type: :integer]
],
request_body: nil,
responses: [
ok: {"organization", "application/json", BuildelWeb.Schemas.Organizations.ShowResponse},
not_found: {"not_found", "application/json", BuildelWeb.Schemas.Errors.NotFoundResponse},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

def show(conn, %{"id" => organization_id}) do
user = conn.assigns.current_user

Expand All @@ -25,6 +53,22 @@ defmodule BuildelWeb.OrganizationController do
end
end

operation :create,
summary: "Create organization",
parameters: [],
request_body:
{"organization", "application/json", BuildelWeb.Schemas.Organizations.CreateRequest},
responses: [
created:
{"organization", "application/json", BuildelWeb.Schemas.Organizations.ShowResponse},
unprocessable_entity:
{"unprocessable entity", "application/json",
BuildelWeb.Schemas.Errors.UnprocessableEntity},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

defparams :create do
required(:organization, :map) do
required(:name, :string)
Expand All @@ -45,13 +89,30 @@ defmodule BuildelWeb.OrganizationController do
end
end

operation :update,
summary: "Update organization",
parameters: [
id: [in: :path, description: "Organization ID", type: :integer]
],
request_body:
{"organization", "application/json", BuildelWeb.Schemas.Organizations.CreateRequest},
responses: [
ok: {"organization", "application/json", BuildelWeb.Schemas.Organizations.ShowResponse},
not_found: {"not_found", "application/json", BuildelWeb.Schemas.Errors.NotFoundResponse},
unprocessable_entity:
{"unprocessable entity", "application/json",
BuildelWeb.Schemas.Errors.UnprocessableEntity},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

defparams :update do
required(:organization, :map) do
required(:name, :string)
end
end


def update(conn, %{"id" => organization_id} = params) do
user = conn.assigns.current_user

Expand All @@ -60,14 +121,29 @@ defmodule BuildelWeb.OrganizationController do
{:ok, organization} <- Organizations.get_user_organization(user, organization_id),
{:ok, %Organizations.Organization{} = organization} <-
Organizations.update_organization(organization, organization_params) do

conn
|> put_status(:ok)
|> put_resp_header("location", ~p"/api/organizations/#{organization.id}")
|> render(:show, organization: organization)
|> put_status(:ok)
|> put_resp_header("location", ~p"/api/organizations/#{organization.id}")
|> render(:show, organization: organization)
end
end

operation :get_api_key,
summary: "Get organization API key",
parameters: [
id: [in: :path, description: "Organization ID", type: :integer]
],
request_body: nil,
responses: [
ok:
{"organization_key", "application/json",
BuildelWeb.Schemas.Organizations.ShowApiKeyResponse},
not_found: {"not_found", "application/json", BuildelWeb.Schemas.Errors.NotFoundResponse},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

def get_api_key(conn, %{"id" => organization_id}) do
user = conn.assigns.current_user

Expand All @@ -77,6 +153,22 @@ defmodule BuildelWeb.OrganizationController do
end
end

operation :reset_api_key,
summary: "Reset organization API key",
parameters: [
id: [in: :path, description: "Organization ID", type: :integer]
],
request_body: nil,
responses: [
ok:
{"organization_key", "application/json",
BuildelWeb.Schemas.Organizations.ShowApiKeyResponse},
not_found: {"not_found", "application/json", BuildelWeb.Schemas.Errors.NotFoundResponse},
unauthorized:
{"unauthorized", "application/json", BuildelWeb.Schemas.Errors.UnauthorizedResponse},
forbidden: {"forbidden", "application/json", BuildelWeb.Schemas.Errors.ForbiddenResponse}
]

def reset_api_key(conn, %{"id" => organization_id}) do
user = conn.assigns.current_user

Expand Down
14 changes: 14 additions & 0 deletions apps/api/lib/buildel_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule BuildelWeb.Router do
import BuildelWeb.UserAuth
import BuildelWeb.BasicAuth
import Phoenix.LiveDashboard.Router
alias OpenApiSpex.Plug.{RenderSpec, PutApiSpec}

pipeline :browser do
plug(:accepts, ["html"])
Expand All @@ -22,6 +23,13 @@ defmodule BuildelWeb.Router do
pipeline :api do
plug(:accepts, ["json", "sse"])
plug(:fetch_session)
plug(PutApiSpec, module: BuildelWeb.ApiSpec)
end

scope "/" do
pipe_through(:browser)

get "/swaggerui", OpenApiSpex.Plug.SwaggerUI, path: "/api/openapi"
end

scope "/dev" do
Expand Down Expand Up @@ -149,4 +157,10 @@ defmodule BuildelWeb.Router do

post("/channel_auth", ChannelAuthController, :create)
end

scope "/api" do
pipe_through(:api)

get "/openapi", RenderSpec, []
end
end
68 changes: 68 additions & 0 deletions apps/api/lib/buildel_web/schemas/errors.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
defmodule BuildelWeb.Schemas.Errors do
alias OpenApiSpex.Schema

defmodule NotFoundResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
errors: %Schema{
type: :object,
properties: %{
detail: %Schema{type: :string, description: "Error message"}
}
}
}
})
end

defmodule UnauthorizedResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
errors: %Schema{
type: :object,
properties: %{
detail: %Schema{type: :string, description: "Error message"}
}
}
}
})
end

defmodule ForbiddenResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
errors: %Schema{
type: :object,
properties: %{
detail: %Schema{type: :string, description: "Error message"}
}
}
}
})
end

defmodule UnprocessableEntity do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
errors: %Schema{
type: :object,
additionalProperties: %Schema{
type: :array,
items: %Schema{type: :string, description: "Field error message"}
}
}
}
})
end
end
68 changes: 68 additions & 0 deletions apps/api/lib/buildel_web/schemas/organizations.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
defmodule BuildelWeb.Schemas.Organizations do
alias OpenApiSpex.Schema

defmodule Organization do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
id: %Schema{type: :integer, description: "Organization ID"},
name: %Schema{type: :string, description: "Organization name"},
api_key: %Schema{type: :string, description: "Organization API key"}
}
})
end

defmodule IndexResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
data: %Schema{
type: :array,
items: Organization
}
}
})
end

defmodule ShowResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
data: BuildelWeb.Schemas.Organizations.Organization
}
})
end

defmodule CreateRequest do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
name: %Schema{type: :string, description: "Organization name"}
}
})
end

defmodule ShowApiKeyResponse do
require OpenApiSpex

OpenApiSpex.schema(%{
type: :object,
properties: %{
data: %Schema{
type: :object,
properties: %{
key: %Schema{type: :string, description: "Organization API key"}
}
}
}
})
end
end
3 changes: 2 additions & 1 deletion apps/api/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ defmodule Buildel.MixProject do
{:exvcr, "~> 0.15.1", only: :test},
{:joken, "~> 2.5"},
{:joken_jwks, "~> 1.6"},
{:resend, "~> 0.4.1"}
{:resend, "~> 0.4.1"},
{:open_api_spex, "~> 3.18"}
]
end

Expand Down
1 change: 1 addition & 0 deletions apps/api/mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"nx": {:hex, :nx, "0.6.1", "df65cd61312bcaa756559fb994596d403c822e353616094fdfc31a15181c95f8", [:mix], [{:complex, "~> 0.5", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "23dcc8e2824a6e19fcdebef39145fdff7625fd7d26fd50c1990ac0a1dd05f960"},
"nx_image": {:hex, :nx_image, "0.1.1", "69cf0d2fd873d12b028583aa49b5e0a25f6aca307afc337a5d871851a20fba1d", [:mix], [{:nx, "~> 0.4", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "55c8206a822237f6027168f11214e3887263c5b8a1f8e0634eea82c96e5093e3"},
"nx_signal": {:hex, :nx_signal, "0.2.0", "e1ca0318877b17c81ce8906329f5125f1e2361e4c4235a5baac8a95ee88ea98e", [:mix], [{:nx, "~> 0.6", [hex: :nx, repo: "hexpm", optional: false]}], "hexpm", "7247e5e18a177a59c4cb5355952900c62fdeadeb2bad02a9a34237b68744e2bb"},
"open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [: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 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"},
"openai": {:hex, :openai, "0.5.4", "2abc7bc6a72ad1732c16d3f0914aa54f4de14b174a4c70c1b2d7934f0fe2646f", [:mix], [{:httpoison, "~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "72add1d3dcbf3ed7d24ce3acf51e8b2f374b23305b0fc1d5f6acff35c567b267"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"pgvector": {:hex, :pgvector, "0.2.1", "dc707ce6065ac0e82e5716bc17f9c6a97f92aca23994e5cceef7dfc48bb57eed", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "ed86c560af2f85b31d79f119192ce98f3342b4d06ceac63824a8686fe07e59b6"},
Expand Down

0 comments on commit c0c7419

Please sign in to comment.