Skip to content

Commit

Permalink
Add Apps GET API documentation (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomkonidas authored Sep 6, 2024
1 parent 9dc09b1 commit eff2912
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 5 deletions.
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"},
}

0 comments on commit eff2912

Please sign in to comment.