Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Apps GET API documentation #363

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
import_deps: [:ecto, :ecto_sql, :phoenix],
import_deps: [:open_api_spex, :ecto, :ecto_sql, :phoenix],
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 config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ config :plexus, Plexus.Repo,
show_sensitive_data_on_connection_error: true,
pool_size: 10

config :open_api_spex, :cache_adapter, OpenApiSpex.Plug.NoneCache

# For development, we disable any cache and enable
# debugging and code reloading.
#
Expand Down
17 changes: 17 additions & 0 deletions lib/plexus_web/api_spec.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule PlexusWeb.ApiSpec do
@behaviour OpenApiSpex.OpenApi

@impl OpenApiSpex.OpenApi
def spec do
OpenApiSpex.resolve_schema_modules(%OpenApiSpex.OpenApi{
servers: [
OpenApiSpex.Server.from_endpoint(PlexusWeb.Endpoint)
],
info: %OpenApiSpex.Info{
title: "Plexus",
version: to_string(Application.spec(:plexus, :vsn))
},
paths: OpenApiSpex.Paths.from_router(PlexusWeb.Router)
})
end
end
38 changes: 38 additions & 0 deletions lib/plexus_web/controllers/api/v1/app_controller.ex
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
defmodule PlexusWeb.API.V1.AppController do
use PlexusWeb, :controller
use OpenApiSpex.ControllerSpecs

alias Plexus.Apps
alias PlexusWeb.API.V1.Schemas.AppResponse
alias PlexusWeb.API.V1.Schemas.AppsResponse
alias PlexusWeb.Params

action_fallback PlexusWeb.FallbackController

tags ["apps"]

operation :index,
summary: "List Applications",
parameters: [
page: [in: :query, description: "Page number", type: :integer, example: 2],
limit: [in: :query, description: "Max results per page", type: :integer, example: 25],
scores: [in: :query, description: "Include scores", type: :boolean, example: true],
q: [in: :query, description: "Search query", type: :string, example: "YouTube"]
],
responses: [
ok: {"Applications", "application/json", AppsResponse}
]

def index(conn, params) do
opts = build_opts(params)
page = Apps.list_apps(opts)
render(conn, :index, page: page)
end

operation :create, false

def create(conn, %{"app" => params}) do
schema = %{
package: {:string, required: true},
Expand All @@ -28,6 +47,22 @@ defmodule PlexusWeb.API.V1.AppController do
end
end

operation :show,
summary: "Get Application",
parameters: [
package: [
in: :path,
description: "Android Package",
type: :string,
required: true,
example: "com.google.android.youtube"
],
scores: [in: :query, description: "Include scores", type: :boolean, example: true]
],
responses: [
ok: {"Applications", "application/json", AppResponse}
]

def show(conn, %{"package" => package} = params) do
opts = build_opts(params)
app = Apps.get_app!(package, opts)
Expand All @@ -36,6 +71,9 @@ defmodule PlexusWeb.API.V1.AppController do

defp build_opts(params) do
Enum.reduce(params, [], fn
{"q", search_term}, acc ->
Keyword.put(acc, :search_term, search_term)

{"scores", "true"}, acc ->
Keyword.put(acc, :scores, true)

Expand Down
37 changes: 37 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/app.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule PlexusWeb.API.V1.Schemas.App do
alias OpenApiSpex.Schema
alias PlexusWeb.API.V1.Schemas.Scores
require OpenApiSpex

OpenApiSpex.schema(%{
title: "App",
description: "A Representation of an App",
type: :object,
properties: %{
name: %Schema{type: :string, description: "Name"},
package: %Schema{type: :string, description: "Android Package"},
icon_url: %Schema{type: :string, description: "URL of Icon"},
scores: Scores
},
example: %{
"name" => "YouTube Music",
"package" => "com.google.android.youtube.tvmusic",
"scores" => %{
"native" => %{
"rating_type" => "native",
"numerator" => 1.2,
"total_count" => 21,
"denominator" => 4
},
"micro_g" => %{
"rating_type" => "micro_g",
"numerator" => 4.0,
"total_count" => 44,
"denominator" => 4
}
},
"icon_url" =>
"https://play-lh.googleusercontent.com/76AjYITcB0dI0sFqdQjNgXQxRMlDIswbp0BAU_O5Oob-73b6cqKggVlAiNXQAW5Bl1g"
}
})
end
37 changes: 37 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/app_response.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule PlexusWeb.API.V1.Schemas.AppResponse do
alias PlexusWeb.API.V1.Schemas.App
require OpenApiSpex

OpenApiSpex.schema(%{
title: "AppResponse",
description: "Response schema for an application",
type: :object,
properties: %{
data: App
},
example: %{
"data" => [
%{
"name" => "YouTube Music",
"package" => "com.google.android.youtube.tvmusic",
"scores" => %{
"native" => %{
"rating_type" => "native",
"numerator" => 1.2,
"total_count" => 21,
"denominator" => 4
},
"micro_g" => %{
"rating_type" => "micro_g",
"numerator" => 3.9,
"total_count" => 44,
"denominator" => 4
}
},
"icon_url" =>
"https://play-lh.googleusercontent.com/lMoItBgdPPVDJsNOVtP26EKHePkwBg-PkuY9NOrc-fumRtTFP4XhpUNk_22syN4Datc"
}
]
}
})
end
46 changes: 46 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/apps_response.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule PlexusWeb.API.V1.Schemas.AppsResponse do
alias OpenApiSpex.Schema
alias PlexusWeb.API.V1.Schemas.App
alias PlexusWeb.API.V1.Schemas.Page
require OpenApiSpex

OpenApiSpex.schema(%{
title: "AppsResponse",
description: "Response schema for a list of applications",
type: :object,
properties: %{
data: %Schema{type: :array, items: App},
meta: Page
},
example: %{
"data" => [
%{
"name" => "YouTube Music",
"package" => "com.google.android.youtube.tvmusic",
"scores" => %{
"native" => %{
"rating_type" => "native",
"numerator" => 1.1,
"total_count" => 21,
"denominator" => 4
},
"micro_g" => %{
"rating_type" => "micro_g",
"numerator" => 3.7,
"total_count" => 43,
"denominator" => 4
}
},
"icon_url" =>
"https://play-lh.googleusercontent.com/76AjYITcB0dI0sFqdQjNgXQxRMlDIswbp0BAU_O5Oob-73b6cqKggVlAiNXQAW5Bl1g"
}
],
"meta" => %{
"page_number" => 3,
"limit" => 1,
"total_count" => 420,
"total_pages" => 69
}
}
})
end
22 changes: 22 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/page.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule PlexusWeb.API.V1.Schemas.Page do
alias OpenApiSpex.Schema
require OpenApiSpex

OpenApiSpex.schema(%{
title: "Page",
description: "Page metadata",
type: :object,
properties: %{
page_number: %Schema{type: :integer, description: "Current page number", default: 1},
limit: %Schema{type: :integer, description: "Max results per page", default: 25},
total_count: %Schema{type: :integer, description: "Total count of results", readOnly: true},
total_pages: %Schema{type: :integer, description: "Total count of pages", readOnly: true}
},
example: %{
"page_number" => 3,
"limit" => 25,
"total_count" => 420,
"total_pages" => 69
}
})
end
22 changes: 22 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/score.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule PlexusWeb.API.V1.Schemas.Score do
alias OpenApiSpex.Schema
require OpenApiSpex

OpenApiSpex.schema(%{
title: "Score",
description: "A Representation of a Score",
type: :object,
properties: %{
rating_type: %Schema{type: :string, description: "Rating Type", enum: ["micro_g", "native"]},
numenator: %Schema{type: :number, description: "Numenator"},
denominator: %Schema{type: :integer, description: "Denominator"},
total_count: %Schema{type: :string, description: "Total count of ratings"}
},
example: %{
"numerator" => 4.0,
"denominator" => 4,
"rating_type" => "micro_g",
"total_count" => 69
}
})
end
29 changes: 29 additions & 0 deletions lib/plexus_web/controllers/api/v1/schemas/scores.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule PlexusWeb.API.V1.Schemas.Scores do
alias PlexusWeb.API.V1.Schemas.Score
require OpenApiSpex

OpenApiSpex.schema(%{
title: "Scores",
description: "A Representation of Scores",
type: :object,
properties: %{
micro_g: Score,
native: Score
},
derive?: false,
example: %{
"micro_g" => %{
"numerator" => 4.0,
"denominator" => 4,
"rating_type" => "micro_g",
"total_count" => 69
},
"native" => %{
"numerator" => 3.7,
"denominator" => 4,
"rating_type" => "native",
"total_count" => 69
}
}
})
end
11 changes: 9 additions & 2 deletions lib/plexus_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule PlexusWeb.Router do

pipeline :api do
plug :accepts, ["json"]
plug OpenApiSpex.Plug.PutApiSpec, module: PlexusWeb.ApiSpec
end

pipeline :authenticated_device do
Expand All @@ -22,10 +23,11 @@ defmodule PlexusWeb.Router do
plug :auth
end

scope "/", PlexusWeb do
scope "/" do
pipe_through :browser

live "/", AppLive.Index, :index
live "/", PlexusWeb.AppLive.Index, :index
get "/swaggerui", OpenApiSpex.Plug.SwaggerUI, path: "/api/openapi"
end

scope "/admin", PlexusWeb.Admin do
Expand All @@ -41,6 +43,11 @@ defmodule PlexusWeb.Router do
live "/apps/:package/ratings/:rating_type", RatingLive.Index, :index
end

scope "/api" do
pipe_through :api
get "/openapi", OpenApiSpex.Plug.RenderSpec, []
end

scope "/api/v1", PlexusWeb.API.V1 do
pipe_through :api

Expand Down
6 changes: 4 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Plexus.MixProject do
def project do
[
app: :plexus,
version: "0.1.0",
version: "1.0.0",
elixir: "~> 1.15",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down Expand Up @@ -59,7 +59,9 @@ defmodule Plexus.MixProject do
{:plug_cowboy, "~> 2.6"},
{:swoosh, "~> 1.3"},
{:gen_smtp, "~> 1.2"},
{:finch, "~> 0.13"}
{:finch, "~> 0.13"},
{:open_api_spex, "~> 3.20"},
{:ymlr, "~> 5.1"}
]
end

Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"nimble_totp": {:hex, :nimble_totp, "1.0.0", "79753bae6ce59fd7cacdb21501a1dbac249e53a51c4cd22b34fa8438ee067283", [:mix], [], "hexpm", "6ce5e4c068feecdb782e85b18237f86f66541523e6bad123e02ee1adbe48eda9"},
"open_api_spex": {:hex, :open_api_spex, "3.20.1", "ce5b3db013cd7337ab147f39fa2d4d627ddeeb4ff3fea34792f43d7e2e654605", [: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 or ~> 6.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "dc9c383949d0fc4b20b73103ac20af39dad638b3a15c0e6281853c2fc7cc3cc8"},
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [: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.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
Expand All @@ -49,4 +50,5 @@
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
"ymlr": {:hex, :ymlr, "5.1.3", "a8061add5a378e20272a31905be70209a5680fdbe0ad51f40cb1af4bdd0a010b", [:mix], [], "hexpm", "8663444fa85101a117887c170204d4c5a2182567e5f84767f0071cf15f2efb1e"},
}
Loading