diff --git a/test/plug/cast_test.exs b/test/plug/cast_test.exs index 22b7e78f..d787ab7b 100644 --- a/test/plug/cast_test.exs +++ b/test/plug/cast_test.exs @@ -51,6 +51,34 @@ defmodule OpenApiSpex.Plug.CastTest do assert OpenApiSpex.params(conn) == %{validParam: true} end + test "handles multipart/form-data array parameters" do + boundary = "----testboundary" + + body = """ + --#{boundary}\r + Content-Disposition: form-data; name="files[]"; filename="file1.txt"\r + Content-Type: text/plain\r + \r + HI\r + --#{boundary}\r + Content-Disposition: form-data; name="files[]"; filename="file2.txt"\r + Content-Type: text/plain\r + \r + HI2\r + --#{boundary}--\r + """ + + conn = + Plug.Test.conn(:post, "/api/upload_multipart", body) + |> Plug.Conn.put_req_header("content-type", "multipart/form-data; boundary=#{boundary}") + |> Plug.Conn.put_req_header("accept", "application/json") + |> OpenApiSpexTest.Router.call([]) + + body = Jason.decode!(conn.resp_body) + + assert %{"data" => ["file1.txt", "file2.txt"]} = body + end + @tag :capture_log test "invalid value" do conn = diff --git a/test/support/router.ex b/test/support/router.ex index 89cc5b59..026a198b 100644 --- a/test/support/router.ex +++ b/test/support/router.ex @@ -6,7 +6,7 @@ defmodule OpenApiSpexTest.Router do pipeline :api do plug :accepts, ["json"] plug PutApiSpec, module: OpenApiSpexTest.ApiSpec - plug Parsers, parsers: [:json], pass: ["text/*"], json_decoder: Jason + plug Parsers, parsers: [:json, :multipart], pass: ["text/*"], json_decoder: Jason end scope "/api" do @@ -25,6 +25,7 @@ defmodule OpenApiSpexTest.Router do get "/users/:id/payment_details", OpenApiSpexTest.UserController, :payment_details post "/users/:id/contact_info", OpenApiSpexTest.UserController, :contact_info post "/users/create_entity", OpenApiSpexTest.UserController, :create_entity + post "/upload_multipart", OpenApiSpexTest.UploadMultipartController, :create get "/openapi", OpenApiSpex.Plug.RenderSpec, [] resources "/pets", OpenApiSpexTest.PetController, only: [:create, :index, :show, :update] diff --git a/test/support/schemas.ex b/test/support/schemas.ex index 65f687fd..c4921f84 100644 --- a/test/support/schemas.ex +++ b/test/support/schemas.ex @@ -278,6 +278,29 @@ defmodule OpenApiSpexTest.Schemas do }) end + defmodule UploadRequest do + OpenApiSpex.schema(%{ + title: "UploadRequest", + description: "POST body for uploading files", + type: :object, + properties: %{ + "files[]": %Schema{type: :array, items: %Schema{type: :string, format: :binary}} + }, + required: [:"files[]"] + }) + end + + defmodule UploadResponse do + OpenApiSpex.schema(%{ + title: "UploadResponse", + description: "", + type: :object, + properties: %{ + data: %Schema{description: "Filenames", type: :array, items: %Schema{type: :string}} + } + }) + end + defmodule UserRequest do OpenApiSpex.schema(%{ title: "UserRequest", diff --git a/test/support/upload_multipart_controller.ex b/test/support/upload_multipart_controller.ex new file mode 100644 index 00000000..a80fa908 --- /dev/null +++ b/test/support/upload_multipart_controller.ex @@ -0,0 +1,20 @@ +defmodule OpenApiSpexTest.UploadMultipartController do + @moduledoc tags: ["uploads"] + + use Phoenix.Controller + use OpenApiSpex.Controller + + alias OpenApiSpexTest.Schemas + + plug OpenApiSpex.Plug.CastAndValidate, json_render_error_v2: true, replace_params: false + + @doc request_body: {"Files", "multipart/form-data", Schemas.UploadRequest}, + responses: [ + created: {"Files", "application/json", Schemas.UploadResponse} + ] + def create(conn, %{"files" => files}) do + json(conn, %Schemas.UploadResponse{ + data: Enum.map(files, & &1.filename) + }) + end +end