Request: Add Resource Object Model specifications
What is this?
I think it would be nice to have a new feature to add in Resource Object Models. These describe an object that would be returned by a call to a resource endpoint. An example of such a thing could be seen by browsing other companies documentation like discord, stripe, etc.
These are helpful to know what someone reading the documentation should expect from any given resource call, be it posting, getting, or patching.
How should this look?
My thoughts would be that we have something like parameter, but at the resource level only. I actually already kinda started on this and defined resource_attribute as a resource level method that takes a name, type, description, and scope. In a spec file, It would look like this:
resource "Order" do
explanation "An `order` object represents the contents of a given sale. This includes food, drinks, who it goes to, and more."
resource_attribute :id, "The id of an order", type: :integer
resource_attribute :type, "The type of order this is. This should could be `open_order`, `past_order`, of `future_order`.", type: :Text
resource_attribute :name, "The name of the individual that placed the order.", type: :text, scope: :attributes
resource_attribute :fulfilled, "Whether this order has been fulfilled or not.", type: :boolean, scope: :attributes
resource_attribute :notes, "Any notes associated with an order", type: :text, scope: :attributes
...
Just like with parameters, the resource attributes can take a scope the helps identify how the object is structured.
What is the "spec-able" purpose of this?
I think that the resource attributes could be used to test that responses from the API are validated with the resource object definition. This can be the case for both single object responses and even object collection responses where each object in the collection could be validated (or just the first object in the collection). In order to not break any currently existing workflows, this can be an opt-in configuration option :validates_resource. Even further, there can be an example level metadata key :skip_resource_validation that can allow the example to test as normal without validating it's response against the resource object model.
What is the difficulty of this?
In truth, recording this extra information is fairly easy... and I managed to do in a matter of hours. The real challenge lies is adding this info into the different formats like slate, json, html, markdown, textile, etc. I also noticed that the APIBlueprint addition seems to have added something similar to what I am looking for after I had put in a bunch of work for this. However, I don't think it is quite the same, and also does not employ the idea of resource model validation.
Please share any thoughts and comments. I would love to see this be a great new feature of RAD!
Hey @E1337Kat, I think this might exist already? The response_field field DSL. It might not be in all of the formats, but I think the HTML and general JSON format should have it.
If you want to work on validating the response matches what the response_field says, I'd be happy to look over a PR! Also for any changes you might want to make to response_field. I expect it doesn't handle recording object fields nicely, for instance.
I have used response_field before, but it is more endpoint specific rather than resource specific fields... I will concede though that it would essentially be the same data (minus taking the type metadata for the field... which would be required I think).
I could see how the resource object model could be built from the resource_field given in each endpoint... Hmmm. I will think on this.
Ah OK, I see what you mean. I think a more general object DSL makes sense then. It might be worth booting this from the current DSL and have something more similar to spec/factories.rb. We could probably generate JSON Schema and drop it in your generated folder.
Seems like a neat idea to open up some new possibilities.
How would you see this working then?
For the general object DSL, I could see having it just be nested under resource and it could take some parameter/attribute/field/whatever you call it, and then just include all of the other endpoing DSLs in that or concurrent with that one... Like saying "when describing this resource when this object is returned [other context] it/expect something."? I think that would actually make sense as you then group together all of the examples that would return an object of the resource, but also if for some reason your resource endpoint returns a different object, it could still be in the same spec. I also can see that not all endpoints of a resource need to return something.... so this case works for that. It'd probably look something like:
resource "Order" do
object do
param/attribute/field :id "the id of this object.", type: "integer"
...
get '/v1/order/:id' do
example_request "Get a specific order" do
expect(status).to eq 200
expect(response_body).to verify object #or something, maybe just check it includes json
end
end
end
delete '/v1/order/:id' do
example_request 'Delete an order.' do
expect(status).to eq 302
end
end
# Even more is possible including error testing... I have other ideas for errors though.
end
For breaking off into something akin to spec/factories.rb, I don't really know how this would look. I admit I am not as familiar with it's inner workings as I am of this and rspec. However, with a quick glance over, I have an idea as to how this would look, and might work... but would need time to really dig and understand how it works.
I agree that this could be very useful outside of my initial intended purpose. :)