skryukov / skooma

Skooma is a Ruby library for validating API implementations against OpenAPI documents.
MIT License
140 stars 5 forks source link

Uploading file ActiveStorage #16

Open ShonRepo opened 8 months ago

ShonRepo commented 8 months ago

Hey! If I upload a file using the as: :json post method, I get this error

ArgumentError: missing keywords: :io, :filename

but, not use as: :json, the file is loading successfully, but if there is a body required parameter in the openapi schema, then I get the error body id required

code:

    describe "POST" do
      let_it_be(:test_file) { file_fixture("image.jpeg") }
      let_it_be(:file_upload) { fixture_file_upload(test_file, "image/jpeg") }

      let(:body) do
        {
          ...
          image: file_upload
        }
      end

      subject { post "path", params: body, as: :json }

      context "success" do
        it { is_expected.to conform_schema(201) }
      end
    end
  end
skryukov commented 5 months ago

Hey, @ShonRepo! I just released a new version of gem with a limited support of binary files validation. Here is an example:

# docs/openapi.yaml
#...

paths:
  /upload:
    post:
      summary: Example of Active Storage upload
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file: {}

      responses:
        "200":
           description: successful operation
        "422":
           $ref: '#/components/responses/ErrorResponse'

To work with multipart/form-data responses we need to register a new parser (will probably add that parser into a gem eventually):

# spec/rails_helper.rb
#...

Skooma::BodyParsers.register("multipart/form-data", ->(body, headers:) do
    info = Rack::Multipart::Parser.parse(
      StringIO.new(body),
      headers["Content-Length"].to_i,
      headers["Content-Type"],
      ->(*) { String.new },
      Rack::Multipart::Parser::BUFSIZE,
      Rack::Utils.default_query_parser,
    )
    info.params
  end)

Now it's possible to validate requests:

# spec/requests/upload_spec.rb
# ...
  describe "POST /upload" do
    subject { post("/upload", params:) }

    let(:test_file) { file_fixture("image.jpeg") }
    let(:file) { fixture_file_upload(test_file, "image/jpeg") }

    let(:params) { {file:} }

    it { is_expected.to conform_schema(200) }

    context "without file" do
      let(:file) { nil }

      it { is_expected.to conform_response_schema(422) }
    end
  end