Skip to content

Commit

Permalink
Merge pull request #5 from cciuenf/feature/swagger
Browse files Browse the repository at this point in the history
feature/swagger
  • Loading branch information
Matheus de Souza Pessanha authored Jul 28, 2021
2 parents fe20e96 + 5616a62 commit 9ad3086
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 1 deletion.
21 changes: 21 additions & 0 deletions lib/fuschia_web/router.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
defmodule FuschiaWeb.Router do
use FuschiaWeb, :router

pipeline :browser do
plug :accepts, ["html"]
end

pipeline :api do
plug :accepts, ["json"]
plug FuschiaWeb.LocalePlug
plug ProperCase.Plug.SnakeCaseParams
end

pipeline :api_swagger do
plug :accepts, ["json"]
plug OpenApiSpex.Plug.PutApiSpec, module: FuschiaWeb.Swagger.ApiSpec
end

scope "/" do
pipe_through :browser

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

scope "/api" do
pipe_through :api_swagger

get "/openapi", OpenApiSpex.Plug.RenderSpec, []
end

scope "/api", FuschiaWeb do
pipe_through :api
end
Expand Down
41 changes: 41 additions & 0 deletions lib/fuschia_web/swagger/api_spec.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule FuschiaWeb.Swagger.ApiSpec do
@moduledoc false

alias OpenApiSpex.{Components, Info, OpenApi, Paths, SecurityScheme, Server}
alias FuschiaWeb.{Endpoint, Router}

@behaviour OpenApi

@impl OpenApi
def spec do
%OpenApi{
components: %Components{
securitySchemes: %{
"api_key_header" => %SecurityScheme{
type: "apiKey",
in: "header",
name: "X-API-KEY"
},
"api_key_query" => %SecurityScheme{
type: "apiKey",
in: "query",
name: "api_key"
},
"authorization" => %SecurityScheme{
type: "http",
scheme: "bearer"
}
}
},
servers: [
Server.from_endpoint(Endpoint)
],
info: %Info{
title: "Fuschia API",
version: "0.0.1"
},
paths: Paths.from_router(Router)
}
|> OpenApiSpex.resolve_schema_modules()
end
end
93 changes: 93 additions & 0 deletions lib/fuschia_web/swagger/error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
defmodule FuschiaWeb.Swagger.Error do
@moduledoc false

require OpenApiSpex
alias OpenApiSpex.Schema

defmodule Unauthorized do
@moduledoc false

OpenApiSpex.schema(%{
title: "Unauthorized",
description: "Unauthorized access. Invalid/missing api key or jwt user token."
})
end

defmodule Forbidden do
@moduledoc false

OpenApiSpex.schema(%{
title: "Forbidden",
description: "Access Denied. You don't have permission to access"
})
end

defmodule ErrorMessage do
@moduledoc false

OpenApiSpex.schema(%{
title: "ErrorBody",
description: "Generic error body",
type: :object,
properties: %{
error: %Schema{
type: :object,
properties: %{
details: %Schema{type: :string, description: "Error message"}
}
}
}
})
end

defmodule ConflictMessage do
@moduledoc false

OpenApiSpex.schema(%{
title: "ConflictErrorBody",
description: "Conflict error body",
type: :object,
properties: %{
details: %Schema{type: :string, description: "The item already exists"},
resourceId: %Schema{type: :integer, description: "The item id"}
}
})
end

defmodule GenericError do
@moduledoc false

OpenApiSpex.schema(%{
title: "Error",
description: "Generic error message",
type: :object,
properties: %{
error: ErrorMessage
},
example: %{
"error" => %{
"details" => "The item you requested doesn't exist"
}
}
})
end

defmodule ConflictError do
@moduledoc false

OpenApiSpex.schema(%{
title: "ConflictError",
description: "Error message for conflicts ocurred when creating resources",
type: :object,
properties: %{
error: ConflictMessage
},
example: %{
"error" => %{
"details" => "The item already exists",
"resourceId" => 1
}
}
})
end
end
29 changes: 29 additions & 0 deletions lib/fuschia_web/swagger/response.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule FuschiaWeb.Swagger.Response do
@moduledoc false

alias FuschiaWeb.Swagger.Error

@type response_error :: Error.GenericError | Error.Unauthorized

@spec errors(list) :: [{atom, String.t(), response_error()}]
def errors(options) when is_list(options) do
Enum.map(options, &get_error/1)
end

@spec errors(atom) :: [{atom, String.t(), response_error()}]
def errors(key) do
[get_error(key)]
end

defp get_error(key) do
errors = %{
not_found: {"Not found, inexistent ID", "application/json", Error.GenericError},
unauthorized:
{"Unauthorized access. Invalid/missing API key or JWT token", "application/json",
Error.Unauthorized},
forbidden: {"Access Denied", "application/json", Error.Forbidden}
}

{key, Map.get(errors, key)}
end
end
154 changes: 154 additions & 0 deletions lib/fuschia_web/swagger/schemas/auth.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
defmodule FuschiaWeb.Swagger.AuthSchemas do
@moduledoc false

require OpenApiSpex
alias OpenApiSpex.Schema

defmodule Login do
@moduledoc false

OpenApiSpex.schema(%{
description: "POST body for Login",
security: [
%{"api_key_header" => []},
%{"api_key_query" => []}
],
type: :object,
properties: %{
email: %Schema{type: :string, description: "User Email"},
password: %Schema{type: :string, description: "User Password", format: "password"}
},
required: [:email, :password],
example: %{
"email" => "[email protected]",
"password" => "123456"
}
})
end

defmodule Signup do
@moduledoc false

OpenApiSpex.schema(%{
description: "POST body for Signup",
type: :object,
properties: %{
nomeCompleto: %Schema{type: :string, description: "User full name"},
email: %Schema{type: :string, description: "User Email"},
cpf: %Schema{type: :string, description: "User CPF"},
password: %Schema{type: :string, description: "User Password", format: "password"},
passwordConfirmation: %Schema{
type: :string,
description: "User Password Confirmation",
format: "password"
}
},
required: [:email, :password, :cpf, :passwordConfirmation],
example: %{
"nomeCompleto" => "Joãozinho Testinho",
"contato" => %{
"email" => "[email protected]",
"celular" => "+55 (71) 99999-9999"
},
"password" => "201763",
"passwordConfirmation" => "201763",
"perfil" => "admin"
}
})
end

defmodule UsuarioClaim do
@moduledoc false

OpenApiSpex.schema(%{
title: "User Data",
description: "User Data Claim",
type: :object,
properties: %{
cpf: %Schema{type: :string, description: "User CPF"},
email: %Schema{type: :string, description: "User Email"},
nomeCompleto: %Schema{type: :string, description: "User Full Name"},
perfil: %Schema{
type: :string,
description: "User's profile",
enum: ["avulso", "admin", "pesquisador", "pescador"]
},
permissoes: %Schema{description: "User Permissions", type: :object}
}
})
end

defmodule Token do
@moduledoc false

OpenApiSpex.schema(%{
title: "Token",
description: "Auth Token",
type: :object,
properties: %{
token: %Schema{type: :string, description: "JWT Token"}
}
})
end

defmodule TokenWithUserClaim do
@moduledoc false

OpenApiSpex.schema(%{
title: "Token with User Claims",
description: "Data Structure with Auth Token and User Claims",
type: :object,
properties: %{
user: UsuarioClaim,
token: Token
}
})
end

defmodule LoginRequest do
@moduledoc false

OpenApiSpex.schema(%{
title: "LoginRequest",
description: "POST body for user login",
type: :object,
properties: %{
email: %Schema{type: :string, description: "User E-mail"},
password: %Schema{type: :string, description: "User Password", format: "password"}
},
required: [:email, :password],
example: %{
"email" => "[email protected]",
"password" => "123456"
}
})
end

defmodule LoginResponse do
@moduledoc false

OpenApiSpex.schema(%{
title: "LoginResponse",
description: "Response schema for Login",
type: :object,
properties: %{
data: TokenWithUserClaim
},
example: %{
"data" => %{
"user" => %{
"cpf" => "999.999.999-99",
"email" => "[email protected]",
"nomeCompleto" => "Joãozinho Testinho",
"perfil" => "pesquisador",
"permissoes" => %{
"relatorio" => ["read", "write"]
}
},
"token" =>
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJzb2xmYWNpbF92MSIsImV4cCI6MTYwMzM4ODIzOCwiaWF0IjoxNjAzMTI5MDM4LCJpc3MiOiJzb2xmYWNpbF92MSIsImp0aSI6ImU1Y2YwZmQzLTQ4MTYtNGQ5OC05MWViLWRjZTFmZDQwYTI2NyIsIm5iZiI6MTYwMzEyOTAzNywic3ViIjoiNiIsInR5cCI6ImFjY2VzcyJ9.eQcZphC32O-oKSmz4ivysDVps4WqMOG6I3H7CHS__2ER_oAxgT1CetmjKaQnIvblfSLpuwDAe7zTlY3VvfkzrQ"
}
}
})
end
end
22 changes: 22 additions & 0 deletions lib/fuschia_web/swagger/schemas/pagination/pagination.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule FuschiaWeb.Swagger.PaginationSchemas do
@moduledoc false

require OpenApiSpex
alias OpenApiSpex.Schema

defmodule Pagination do
@moduledoc false

OpenApiSpex.schema(%{
title: "Pagination",
description: "Values used in pagination",
type: :object,
properties: %{
afterCursor: %Schema{description: "key to next database page", type: :string},
beforeCursor: %Schema{description: "key to previous database page", type: :string},
size: %Schema{description: "Page size value", type: :integer},
count: %Schema{description: "Total number of items", type: :integer}
}
})
end
end
Loading

0 comments on commit 9ad3086

Please sign in to comment.