From 551ceafb1302bff917cfc3a35388022a14a61d0e Mon Sep 17 00:00:00 2001 From: Brian Manifold Date: Wed, 20 Aug 2025 14:08:07 -0700 Subject: [PATCH] fix(portal): REST api updates (#10191) * Minor updates to the REST API to more gracefully handle incorrect input data from requests. * Minor updates to the OpenAPI spec. --- .../api/controllers/fallback_controller.ex | 14 +++++++++ .../api/lib/api/schemas/resource_schema.ex | 7 +++-- ...actor_group_membership_controller_test.exs | 29 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/elixir/apps/api/lib/api/controllers/fallback_controller.ex b/elixir/apps/api/lib/api/controllers/fallback_controller.ex index 91d4eed8f..b323c6ee1 100644 --- a/elixir/apps/api/lib/api/controllers/fallback_controller.ex +++ b/elixir/apps/api/lib/api/controllers/fallback_controller.ex @@ -58,4 +58,18 @@ defmodule API.FallbackController do |> put_view(json: API.ChangesetJSON) |> render(:error, status: 422, changeset: changeset) end + + def call(conn, {:error, :rollback}) do + conn + |> put_status(:unprocessable_entity) + |> put_view(json: API.ErrorJSON) + |> render(:error, status: 422, reason: "Invalid payload") + end + + def call(conn, {:error, :invalid_cursor}) do + conn + |> put_status(:bad_request) + |> put_view(json: API.ErrorJSON) + |> render(:error, reason: "Invalid cursor") + end end diff --git a/elixir/apps/api/lib/api/schemas/resource_schema.ex b/elixir/apps/api/lib/api/schemas/resource_schema.ex index d81fcd94b..3695ebf7d 100644 --- a/elixir/apps/api/lib/api/schemas/resource_schema.ex +++ b/elixir/apps/api/lib/api/schemas/resource_schema.ex @@ -14,7 +14,11 @@ defmodule API.Schemas.Resource do name: %Schema{type: :string, description: "Resource name"}, address: %Schema{type: :string, description: "Resource address"}, address_description: %Schema{type: :string, description: "Resource address description"}, - type: %Schema{type: :string, description: "Resource type"}, + type: %Schema{ + type: :string, + description: "Resource type", + enum: ["cidr", "ip", "dns"] + }, ip_stack: %Schema{ type: :string, description: "IP stack type. Only supported for DNS resources.", @@ -62,7 +66,6 @@ defmodule API.Schemas.Resource do required: [:resource], example: %{ "resource" => %{ - "id" => "42a7f82f-831a-4a9d-8f17-c66c2bb6e205", "name" => "Prod DB", "address" => "10.0.0.10", "address_description" => "Production Database", diff --git a/elixir/apps/api/test/api/controllers/actor_group_membership_controller_test.exs b/elixir/apps/api/test/api/controllers/actor_group_membership_controller_test.exs index b8b997561..51c8013a5 100644 --- a/elixir/apps/api/test/api/controllers/actor_group_membership_controller_test.exs +++ b/elixir/apps/api/test/api/controllers/actor_group_membership_controller_test.exs @@ -119,6 +119,35 @@ defmodule API.ActorGroupMembershipControllerTest do assert resp == %{"error" => %{"reason" => "Bad Request"}} end + test "returns error on invalid group id", %{conn: conn, actor: api_actor} do + attrs = %{"add" => ["00000000-0000-0000-0000-000000000000"]} + + conn = + conn + |> authorize_conn(api_actor) + |> put_req_header("content-type", "application/json") + |> patch("/actor_groups/00000000-0000-0000-0000-000000000000/memberships", + memberships: attrs + ) + + assert resp = json_response(conn, 404) + assert resp == %{"error" => %{"reason" => "Not Found"}} + end + + test "returns error on invalid actor id", %{conn: conn, account: account, actor: api_actor} do + actor_group = Fixtures.Actors.create_group(%{account: account}) + attrs = %{"add" => ["00000000-0000-0000-0000-000000000000"]} + + conn = + conn + |> authorize_conn(api_actor) + |> put_req_header("content-type", "application/json") + |> patch("/actor_groups/#{actor_group.id}/memberships", memberships: attrs) + + assert resp = json_response(conn, 422) + assert resp == %{"error" => %{"reason" => "Invalid payload"}} + end + test "removes actor from group", %{conn: conn, account: account, actor: api_actor} do actor_group = Fixtures.Actors.create_group(%{account: account}) actor1 = Fixtures.Actors.create_actor(%{account: account})