Rswag: Syntax for nested objects (array of objects)

Created on 14 Jun 2018  路  3Comments  路  Source: rswag/rswag

Hi,

Working on the project, where I have nested objects. Didn't find the correct syntax to create test including nested objects.

Posted the same question with examples here:
https://stackoverflow.com/questions/50870744/rswag-nested-objects-rswag-syntax

And found the answer. So if you think it is relevant to open syntax a bit more here, I'll be happy to update documentation wiki accordingly.

Br. Antti

Most helpful comment

@ConorSheehan1 What about a get method? Did you solve it too? I've a weird behaviour with:

path "/bar" do
    get "foo`" do
      # Parameters
      parameter name: :"connection_fields[][field_name]",
                in: :query,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_name: {
                            type: :string,
                            description: "connection fields name",
                            required: true
                        }
                    }
                }
      parameter name: :"connection_fields[][field_value]",
                in: :query,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_value: {
                            type: :string,
                            description: "connection fields value",
                            required: true
                        }
                    }
                }

      response "200", "request created" do
        let("connection_fields[][field_name]") { ["some", "sooome"] }
        let("connection_fields[][field_value]") { ["thing", "thiiing"] }
        # Produces params (very weird way)
        {"connection_fields"=>[{"field_name"=>"some"}, {"field_name"=>"sooome", "field_value"=>"thing"}, {"field_value"=>"thiiing"}], "format"=>:json, "controller"=>"bar", "action"=>"foo"}
      end
   end
end

The previous code works with (only a single duet):

let("connection_fields[][field_name]") { ["some"] }
let("connection_fields[][field_value]") { ["thing"] }
# Produces params
{"connection_fields"=>[{"field_name"=>"some2", "field_value"=>"thing2"}], "format"=>:json, "controller"=>"foo", "action"=>"bar"}

Please note that the following code does not work:

path "/foo" do
    get "bar" do

      # Parameters
      parameter name: :connection_fields,
                in: :body,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_name: {
                            type: :string,
                            description: "connection fields name",
                            required: true
                        },
                        field_value: {
                            type: :string,
                            description: "connection fields value",
                            required: true
                        }
                    }
                }

      response "200", "request created" do
        # In body, ok for a POST
        let(:connection_fields) { {connection_fields: [{ "field_name": "some", "field_value": "thing" },
                                                       { "field_name": "some2", "field_value": "thing2" }]} }
       # produces params
       {"{\"connection_fields\":"=>{"{\"field_name\":\"some\",\"field_value\":\"thing\"},{\"field_name\":\"some2\",\"field_value\":\"thing2\"}"=>{"}"=>nil}}, "format"=>:json, "controller"=>"foo", "action"=>"bar"}
      end
    end
  end

This is the configuration working from Postman as parameters:

image

# produces params
{"connection_fields"=>[{"field_name"=>"aa", "field_value"=>"11"}, {"field_name"=>"bb", "field_value"=>"22"}], "format"=>:json, "controller"=>"foo", "action"=>"bar"}

All 3 comments

I've been stuck on the same problem.

I have a controller that expects params like this: {"objects":[{"k":"v"}]}
Ideally I'd document that like this, but it produces the wrong params.

post 'foo' do
  produces 'application/json'
  consumes 'application/json'
  parameter name: :objects, description: 'array of objects', in: :body, schema: {
    type: :array,
    items: {
      type: :object
    }
  }

  response "200", "Objects found" do
    let(:objects) { [{k:'v'}] }
    # produces params
    {"_json"=>[{"k"=>"v"}], "controller"=>"objects", "action"=>"index", "object"=>{"_json"=>[{"k"=>"v"}]}}
  end

end

However, I did find a hack that produces the param I want.

  response "200", "Objects found" do
    let(:objects) { {objects: [{k:'v'}]} }
    # produces params
    {"objects"=>[{"k"=>"v"}], "controller"=>"objects", "action"=>"index", "object"=>{"objects"=>[{"k"=>"v"}]}}
  end

Is there a way to ensure that inner object with _json as they key is not added when using the correct form?

let(:objects) { [{k:'v'}] }

System info

  • rswag-specs (2.0.5)
  • rswag-api (2.0.5)
  • ruby 2.4.4

@ConorSheehan1 What about a get method? Did you solve it too? I've a weird behaviour with:

path "/bar" do
    get "foo`" do
      # Parameters
      parameter name: :"connection_fields[][field_name]",
                in: :query,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_name: {
                            type: :string,
                            description: "connection fields name",
                            required: true
                        }
                    }
                }
      parameter name: :"connection_fields[][field_value]",
                in: :query,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_value: {
                            type: :string,
                            description: "connection fields value",
                            required: true
                        }
                    }
                }

      response "200", "request created" do
        let("connection_fields[][field_name]") { ["some", "sooome"] }
        let("connection_fields[][field_value]") { ["thing", "thiiing"] }
        # Produces params (very weird way)
        {"connection_fields"=>[{"field_name"=>"some"}, {"field_name"=>"sooome", "field_value"=>"thing"}, {"field_value"=>"thiiing"}], "format"=>:json, "controller"=>"bar", "action"=>"foo"}
      end
   end
end

The previous code works with (only a single duet):

let("connection_fields[][field_name]") { ["some"] }
let("connection_fields[][field_value]") { ["thing"] }
# Produces params
{"connection_fields"=>[{"field_name"=>"some2", "field_value"=>"thing2"}], "format"=>:json, "controller"=>"foo", "action"=>"bar"}

Please note that the following code does not work:

path "/foo" do
    get "bar" do

      # Parameters
      parameter name: :connection_fields,
                in: :body,
                type: :array,
                collectionFormat: :multi,
                required: true,
                schema: {
                    type: :object,
                    properties: {
                        field_name: {
                            type: :string,
                            description: "connection fields name",
                            required: true
                        },
                        field_value: {
                            type: :string,
                            description: "connection fields value",
                            required: true
                        }
                    }
                }

      response "200", "request created" do
        # In body, ok for a POST
        let(:connection_fields) { {connection_fields: [{ "field_name": "some", "field_value": "thing" },
                                                       { "field_name": "some2", "field_value": "thing2" }]} }
       # produces params
       {"{\"connection_fields\":"=>{"{\"field_name\":\"some\",\"field_value\":\"thing\"},{\"field_name\":\"some2\",\"field_value\":\"thing2\"}"=>{"}"=>nil}}, "format"=>:json, "controller"=>"foo", "action"=>"bar"}
      end
    end
  end

This is the configuration working from Postman as parameters:

image

# produces params
{"connection_fields"=>[{"field_name"=>"aa", "field_value"=>"11"}, {"field_name"=>"bb", "field_value"=>"22"}], "format"=>:json, "controller"=>"foo", "action"=>"bar"}

The solution above helped me for my use case.

      parameter name: :"location_uuids[]",
                description: "",
                in: :query,
                type: :string,
                schema: { type: :array, items: { type: :string, format: :uuid } },
                required: true
response '200', 'test' do
        let("location_uuids[]") { Location.limit(2).map{ |l| l.id }.join(",") }

In controller

permitted_params = params.permit(
          :location_uuids => []
        )

where permitted_params appears as

{"location_uuids"=>["8fd40c5e-d8c5-4c93-99f3-16238f22838d,607176a3-8625-4f22-9f89-485311420c76"]}

Exactly what I expect it to be.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PhilippeChab picture PhilippeChab  路  4Comments

salzig picture salzig  路  5Comments

richthedev picture richthedev  路  5Comments

Kutomore picture Kutomore  路  3Comments

Kutomore picture Kutomore  路  3Comments