How to pass complex queries in REST?

2019-06-18 16:44发布

问题:

If I understand correctly, in rest style, every query (that is, every action on every resource that does not modifies the resource's state) should be encoded in the query string, using a get method, with no body at all.

Am I right?

Well, I have several applications that communicate with the db thru an XML message that is handled by a Visual Basic 6 component.

the message for a query is something like this

<xml>
  <service>account</service>
  <resource>invoice</resource>
  <action>query</action>
  <parameters>
    <page>1</page>
    <page_len>10</page_len>
    <order>date</order>
    <fields>*</fields>
    <conditions>
      <date>2009-01-01..2009-01-31</date>
      <customer_id>24</customer_id>
    </conditions>
  </parameters>
</xml>

Right now we are in the process of redesigning our XML messages, and we'd like to do that in such a way that they could be easily mapped to a RESTful interface.

In the previous example, we need the "conditions" tags in order to prevent collisions between the parameters and the conditions (i.e., what happens if I have a field named "order", "page" or something like that...

We though about sending the parameters with a prefix, something like

http://account/invoice/?_page=1&_page_len=10&_order=date&_fields=*&date=2009-01-01..2009-01-31&customer_id=24

and the XML would be something like

[...]
    <_order>date</_order>
    <_fields>*</_fields>
    <date>2009-01-01..2009-01-31</date>
    <customer_id>24</customer_id>
[...]

We are trying to define some really simple XML format for crud operations, and that the resulting XML could be easily mapped to rest or JSON.

How would you map that kind of query in a rest application? Is there some standard defined? or some page with crud rest / XML /JSON samples? how about returning error, or nested datasets?

Thanks a lot.

回答1:

IMHO in order to make your system truly RESTful you must rethink all the messages/queries that you will send.

This part:

<conditions>
  <date>2009-01-01..2009-01-31</date>
  <customer_id>24</customer_id>
</conditions>

is the tricky part. What kind of other conditions do you have? Are there many? This particular example makes me think that you can treat invoices as a subresource of a customer. When I do rest I always try to identify resource in the path and if a query stil needs any parameters, I move them to query string. So I'd write something like this:

GET /customers/24/invoices?start_date=2009-01-01&end_date=2009-01-31

Think about relations between your resources. Let's say we have resource type Foo related resource type Bar by a -to-many relation. In this case you can ask about this relation like this: GET /foo/123/bar and add query string parameters to filter it. The problem begins when you want to filter it in a way that involves relations to other resources. IMHO this means that your resource design isn't truly RESTful.



回答2:

You would need to url-encode the xml to be able to pass it, but, if you converted the xml to json then you could pass that string and then json->xml or json->object to process it. This would enable you to pass more complex objects around.

It isn't perfect, but works. :)