Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions test/plug/cast_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
3 changes: 2 additions & 1 deletion test/support/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
Expand Down
23 changes: 23 additions & 0 deletions test/support/schemas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
20 changes: 20 additions & 0 deletions test/support/upload_multipart_controller.ex
Original file line number Diff line number Diff line change
@@ -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},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this could be handled by setting the encoding on the mediaType, something like:

{"Files",
          %{
            "multipart/form-data" => [
              encoding: %{"files" => %OpenApiSpex.Encoding{style: "deepObject"}}
            ]
          }, Schemas.UploadRequest},

However it didn't seem to have any effect on the generated curl commands or request body sent from the swagger UI.

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