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

** (UndefinedFunctionError) function nil.operationId/0 is undefined #447

Merged
merged 9 commits into from
Jul 30, 2022
39 changes: 26 additions & 13 deletions lib/open_api_spex/plug/cast_and_validate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,25 +106,38 @@ defmodule OpenApiSpex.Plug.CastAndValidate do

# This caching is to improve performance of extracting Operation specs
# at runtime when they're using the @doc-based syntax.
operation =
operation_lookup =
case operation_lookup[{controller, action}] do
nil ->
operation_id = controller.open_api_operation(action).operationId

PutApiSpec.get_and_cache_controller_action(
conn,
operation_id,
{controller, action}
)
operation = controller.open_api_operation(action)

if operation do
operation =
PutApiSpec.get_and_cache_controller_action(
conn,
operation.operationId,
{controller, action}
)

{:found_it, operation}
else
# this is the case when operation: false was used
{:skip_it, nil}
end

operation ->
operation
{:found_it, operation}
end

if operation.operationId do
call(conn, Map.put(opts, :operation_id, operation.operationId))
else
raise "operationId was not found in action API spec"
case operation_lookup do
{:skip_it, _} ->
conn

{:found_it, nil} ->
raise "operationId was not found in action API spec"

{:found_it, operation} ->
call(conn, opts |> Map.put(:operation_id, operation.operationId))
end
end

Expand Down
52 changes: 36 additions & 16 deletions test/plug/cast_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,28 @@ defmodule OpenApiSpex.Plug.CastTest do

alias OpenApiSpexTest.ApiSpec

describe "valid operation (not annotated)" do
test "does not raise an error when the operation is nil set with the operation macro" do
conn =
:get
|> Plug.Test.conn("/api/noapi")
|> OpenApiSpexTest.Router.call([])

assert conn.status == 200
end

test "does not raise an error when the operation is nil set with the open_api_operation function" do
conn =
:get
|> Plug.Test.conn("/api/noapi_with_struct")
|> OpenApiSpexTest.Router.call([])

assert conn.status == 200
end
end

describe "query params - basics" do
test "Valid Param" do
test "valid param" do
conn =
:get
|> Plug.Test.conn("/api/users?validParam=true")
Expand All @@ -18,7 +38,7 @@ defmodule OpenApiSpex.Plug.CastTest do
assert OpenApiSpex.params(conn) == %{validParam: true}
end

test "Valid Param with replace_params false" do
test "valid param with replace_params false" do
conn =
:get
|> Plug.Test.conn("/api/users_no_replace?validParam=true")
Expand All @@ -32,7 +52,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid value" do
test "invalid value" do
conn =
:get
|> Plug.Test.conn("/api/users?validParam=123")
Expand All @@ -42,7 +62,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid Param" do
test "invalid param" do
conn =
:get
|> Plug.Test.conn("/api/users?validParam=123")
Expand Down Expand Up @@ -100,7 +120,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

describe "query params - param with custom error handling" do
test "Valid Param" do
test "valid param" do
conn =
:get
|> Plug.Test.conn("/api/custom_error_users?validParam=true")
Expand All @@ -111,7 +131,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid value" do
test "invalid value" do
conn =
:get
|> Plug.Test.conn("/api/custom_error_users?validParam=123")
Expand All @@ -121,7 +141,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid Param" do
test "invalid param" do
conn =
:get
|> Plug.Test.conn("/api/custom_error_users?validParam=123")
Expand All @@ -133,7 +153,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

describe "body params" do
test "Valid Request" do
test "valid request" do
request_body = %{
"user" => %{
"id" => 123,
Expand Down Expand Up @@ -178,7 +198,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid Request" do
test "invalid request" do
request_body = %{
"user" => %{
"id" => 123,
Expand Down Expand Up @@ -207,7 +227,7 @@ defmodule OpenApiSpex.Plug.CastTest do
}
end

test "Valid Request with replace_params false" do
test "valid request with replace_params false" do
request_body = %{
"user" => %{
"id" => 123,
Expand Down Expand Up @@ -253,7 +273,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

describe "oneOf body params" do
test "Valid Request" do
test "valid request" do
request_body = %{
"pet" => %{
"pet_type" => "Dog",
Expand Down Expand Up @@ -285,7 +305,7 @@ defmodule OpenApiSpex.Plug.CastTest do
end

@tag :capture_log
test "Invalid Request" do
test "invalid request" do
request_body = %{
"pet" => %{
"pet_type" => "Human",
Expand All @@ -311,7 +331,7 @@ defmodule OpenApiSpex.Plug.CastTest do
}
end

test "Header params" do
test "header params" do
conn =
:post
|> Plug.Test.conn("/api/pets/1/adopt")
Expand All @@ -327,7 +347,7 @@ defmodule OpenApiSpex.Plug.CastTest do
}
end

test "Optional param" do
test "optional param" do
conn =
:post
|> Plug.Test.conn("/api/pets/1/adopt?status=adopted")
Expand All @@ -343,7 +363,7 @@ defmodule OpenApiSpex.Plug.CastTest do
}
end

test "Cookie params" do
test "cookie params" do
conn =
:post
|> Plug.Test.conn("/api/pets/1/adopt")
Expand All @@ -360,7 +380,7 @@ defmodule OpenApiSpex.Plug.CastTest do
}
end

test "Discriminator with mapping" do
test "discriminator with mapping" do
body =
Jason.encode!(%{
appointment_type: "grooming",
Expand Down
15 changes: 15 additions & 0 deletions test/support/noapi_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule OpenApiSpexTest.NoApiController do
@moduledoc false

use Phoenix.Controller
use OpenApiSpex.ControllerSpecs

plug OpenApiSpex.Plug.CastAndValidate, json_render_error_v2: true
zorbash marked this conversation as resolved.
Show resolved Hide resolved

operation :noapi, false

def noapi(conn, _opts) do
conn
|> put_status(200)
end
end
18 changes: 18 additions & 0 deletions test/support/noapi_controller_with_struct_specs.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule OpenApiSpexTest.NoApiControllerWithStructSpecs do
@moduledoc false

use Phoenix.Controller

plug OpenApiSpex.Plug.CastAndValidate, json_render_error_v2: true

def open_api_operation(action) do
apply(__MODULE__, :"#{action}_operation", [])
end

def noapi_operation(), do: nil
zorbash marked this conversation as resolved.
Show resolved Hide resolved

def noapi(conn, _opts) do
conn
|> put_status(200)
end
end
2 changes: 2 additions & 0 deletions test/support/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ defmodule OpenApiSpexTest.Router do
scope "/api" do
pipe_through :api
resources "/users", OpenApiSpexTest.UserController, only: [:create, :index, :show]
get "/noapi", OpenApiSpexTest.NoApiController, :noapi
get "/noapi_with_struct", OpenApiSpexTest.NoApiControllerWithStructSpecs, :noapi

resources "/users_no_replace", OpenApiSpexTest.UserNoRepalceController, only: [:create, :index]

Expand Down