mattetti / Weasel-Diesel

DSL to describe, document and test web services
MIT License
438 stars 21 forks source link

Problem with response.to_json #18

Closed jarias closed 11 years ago

jarias commented 11 years ago

Hi first of all nice project.

I start using it a couple of days ago and run into an issue with the documentation generation in wd-sinatra I didn't raise the issue there cause it seems to be in the response object of Weasel-Dieasel

Here is the response definition:

  service.response do |response|
    response.object do |obj|
      obj.string :status, :doc => "Response status either OK or ERROR"
      obj.string :message, :doc => "The error message if an error occur", :null => true
      obj.element :name => :payload, :type => 'Resource' do |payload|
        payload.string :id, :doc => "Resource id"
        payload.string :name, :doc => "Resource name"
        payload.string :path, :doc => "Resource full path"
        payload.object :metadata, :doc => "Resource metadata"
        payload.array :tags, :doc => "Resource list of tags"
        payload.datetime :created_at, :doc => "Created at timestamp"
        payload.datetime :updated_at, :doc => "Resource updated at timestamp"
      end
    end
  end

And this is the JSON result of api.response.to_json

{
  "status": "string",
  "message": "string",
  "payload": {
    "payload": {
      "id": "string",
      "name": "string",
      "path": "string",
      "created_at": "datetime",
      "updated_at": "datetime",
      "metadata": {
        "metadata": {

        }
      }
    }
  }
}

If you look at the payload attribute it has a nested payload attribute with the actual payload attributes, thats not what I intended and maybe my declaration is wrong.

This is what I want the payload attribute to look like:

{
  "status": "string",
  "message": "string",
  "payload": {
      "id": "string",
      "name": "string",
      "path": "string",
      "created_at": "datetime",
      "updated_at": "datetime",
      "metadata": {
        "metadata": {

        }
    }
  }
}
mattetti commented 11 years ago

That looks like a bug due to the XML/JSON semantic difference, try:

service.response do |response|
    response.object do |obj|
      obj.string :status, :doc => "Response status either OK or ERROR"
      obj.string :message, :doc => "The error message if an error occur", :null => true
      obj.object :payload do |payload|
        payload.string :id, :doc => "Resource id"
        payload.string :name, :doc => "Resource name"
        payload.string :path, :doc => "Resource full path"
        payload.object :metadata, :doc => "Resource metadata"
        payload.array :tags, :doc => "Resource list of tags"
        payload.datetime :created_at, :doc => "Created at timestamp"
        payload.datetime :updated_at, :doc => "Resource updated at timestamp"
      end
    end
  end

I replaced your use of element with name by object I'm not quite sure why metadata is doubled tho. Let me know if that fixes your problem and we can look in the problem.

jarias commented 11 years ago

Actually I paste the response declaration I was just trying to see if that error would still show up.

This is the correct one:

  service.response do |response|
    response.object do |obj|
      obj.object :payload do |payload|
        payload.string :id, :doc => "Resource id"
        payload.string :name, :doc => "Resource name"
        payload.string :path, :doc => "Resource full path"
        payload.object :metadata, :doc => "Resource metadata"
        payload.array :tags, :doc => "Resource list of tags"
        payload.datetime :created_at, :doc => "Created at timestamp"
        payload.datetime :updated_at, :doc => "Resource updated at timestamp"
      end
    end
  end

And payload and metadata are still duplicated.

mattetti commented 11 years ago

There is something definitely wrong in the JSON representation, probably in https://github.com/mattetti/Weasel-Diesel/blob/master/lib/response.rb#L340-L356 The API usage seems fine so it's probably an issue in the representation. I'll try to reproduce the issue and fix it locally. I know that this part of the code is probably the weakest and it's a shame. Do you use the rake task to generate the doc and that's how you see the json structure?

jarias commented 11 years ago

That is correct I'm using the rake task

jarias commented 11 years ago

I also found another JSON error I was going to log it as a separate ticket.

  service.response do |response|
    response.object do |obj|
      obj.array :payload do |node|
        node.string :id, :doc => "Resource id"
        node.string :name, :doc => "Resource name"
        node.string :path, :doc => "Resource full path"
        node.object :metadata, :doc => "Resource metadata"
        node.array :tags, :doc => "Resource list of tags"
        node.datetime :created_at, :doc => "Created at timestamp"
        node.datetime :updated_at, :doc => "Resource updated at timestamp"
      end
    end
  end

Renders:

{}

:grimacing:

deepj commented 11 years ago

I have the same problem. No attribute in array is converted to json.

deepj commented 11 years ago

For example, this example from README doesn't work properly at all...

      # OUTPUT
      # the response contains a list of player creation ratings each object in the list 
      service.response do |response|
        response.element(:name => "player_creation_ratings") do |e|
          e.attribute  :id          => :integer, :doc => "id doc"
          e.attribute  :is_accepted => :boolean, :doc => "is accepted doc"
          e.attribute  :name        => :string,  :doc => "name doc"

          e.array :name => 'player_creation_rating', :type => 'PlayerCreationRating' do |a|
            a.attribute :comments  => :string,  :doc => "comments doc"
            a.attribute :player_id => :integer, :doc => "player_id doc"
            a.attribute :rating    => :integer, :doc => "rating doc"
            a.attribute :username  => :string,  :doc => "username doc"
          end
        end
      end
kamui commented 11 years ago

I think I fixed both issues.

  1. When calling to_hash, the vectors are totally ignored, which is why arrays are not generated in the response. This was easy to fix, just concat vectors and elements.
  2. As far as I could tell, when invoking to_hash the current element isn't aware of it's parent node. You only need to wrap the element with a key when the element is named and when it's the root node. So I added an optional arg to to_hash called root_node, by default it's true, the recursive calls to to_hash pass false so it's not treated as the root node. This works, but I'm not sure if you would rather link elements together or perhaps there's someway to do this that I missed.