I appreciate this is a complex module and that its use cases are close to infinite, so I might be wrong about this, but why are we sending data on REST services using GET arguments? That's just too limiting and I am really not sure what's the use case for.

Further more, there is already a way to send named arguments on the URL with the @replacement as per

// Replace argument patterns in the operation URL.
    foreach ($arguments as $key => $value) {
      if (strpos($operation_url, '@' . $key) !== FALSE) {
        $operation_url = str_replace('@' . $key, $value, $operation_url);
        unset($arguments[$key]);
      }
    }

I am proposing to send the data directly in the content part of the request than in the URL argument.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

hanoii’s picture

Title: Rest server should send that as post » REST server should send data within the CONTENT
FileSize
790 bytes
hanoii’s picture

Title: REST server should send data within the CONTENT » REST server should send data within the http content part
dman’s picture

Status: Active » Needs work

While it may be possible that someone has built a REST server that expects it's parameters to be sent as content... That's not the way I've usually seen GET requests work at all.

Pretty much every REST service I've seen documented places its arguments in the path, and/or as GET arguments. I've not seen any spec that does it the way you suggest, but if you can refer to such docs, there may be possibilities for it to be supported also.
What is it that makes you claim "REST server should send data within the http content"? Where did you find that idea? I can't remember seeing anything like that in any spec or documentation

Here for example is a simple public REST service. Currently, it works. (test it using a city name). With your patch, it no longer works.

{
  "settings" : [],
  "operations" : { "weather" : {
      "type" : "GET",
      "url" : "weather",
      "label" : "Weather",
      "parameter" : { "q" : { "type" : "text", "allow null" : 0 } }
    }
  },
  "datatypes" : [],
  "global_parameters" : [],
  "name" : "openweathermaps",
  "label" : "OpenWeathermaps",
  "url" : "http:\/\/api.openweathermap.org\/data\/2.5\/",
  "type" : "rest",
  "authentication" : null,
  "rdf_mapping" : []
}

If you see docs and tutorials, they usually pass parameters in this way, and that has also been true of the real-world web services I've plugged in to.

http://MyService/Persons/1?format=xml&encoding=UTF8
http://www.acme.com/phonebook/UserDetails?firstName=John&lastName=Doe
http://md5.jsontest.com/?text=convert%20this
http://jsonplaceholder.typicode.com/posts?userId=1

... your patch breaks these examples.

Until they added extra authentication, the Twitter search, and Facebook opengraph also do thishttps://graph.facebook.com/bgolub?fields=id%2Cname%2Cpicture

If you can provide working public test cases and docs for the protocol that does it your way, it's possible that this could be supported as well, but right now, what you are proposing would break all the current REST services that *do* work with GET arguments.

hanoii’s picture

I think I might have jumped too quickly to this assumption, basically I am not bothered by GET request.

My assumption was that when you actually need params in the GET request, you could still do so by doing something like (for your example):

openweathermaps?q=@q

This is currently supported like this in the REST module. But I see how my patch can break currently configured working web services.

I got to this patch while needing to POST/PUT data in which, I believe, you normally sends information through the DATA part of the request, see:

https://developers.facebook.com/docs/graph-api/reference/v2.2/user/feed (the publishing part) as an example.

What about the following patch, in which you sends the arguments on the DATA part of the post for POST/PUT entries, but leave the current logic for GET and possible DELETE, I am unsure of the last one but for now at least POST/PUT would work.

hanoii’s picture

Status: Needs work » Needs review
dman’s picture

That makes more sense.
If you are talking about POST not working right for you, then yeah, it's probable that that hasn't been getting fully supported until now.
TBH, I've not used POST with any live REST service, because
A: most of the time I'm just consuming data
B: if things are getting tricky and transactional, it has probably become a job for SOAP.
... but still, REST+POST should indeed be supported properly.

Although technically legal, I've not found a sane real-world service that required both GET and POST in the same action, so I think that your logic in #4 for switching the argument encoding depending on GET/POST is totally reasonable.

I'm not keen on introducing placeholder weirdness to the URL strings. That gets odd, you have to deal with the difference between param= {empty string} and param being undefined. Plus possible multiples or structured params (rare). Plus string encoding issues (common)
Let's not mess with that idea.

But this second patch has legs.

Can you point us at a public web service that demonstrates its use so it can become testable?

hanoii’s picture

The placeholder weirdness is already there in the code, my point was that as that was there, you could use it for GET request, but this approach still cope with both ways.

Let me see if I find something, normally a public service won't allow you to post anything to it, you usually post something when you need to modify/create something and for that you usually needs authentication.

georgir’s picture

Title: REST server should send data within the http content part » REST client should send data within the http content part
georgir’s picture

It seems you could define a single parameter (potentially of a compound type) and set $operation['data'] = '[name of your parameter]' to get this effect without a patch. But it would indeed complicate invoking the service with having to wrap the parameters in one more array().

Maybe we can use some special value of $operation['data'], such as empty string, to trigger using all the remaining parameters as data, instead of defaulting to it? Or default to it, and use a special value to trigger the old functionality, with leaving $arguments as is?

The current patch just completely removes $operation['data'] functionality from POST and PUT requests, which does not seem consistent.

And slightly related to this, we'd also need to add $operation['data'] to the UI.

skek’s picture

Based on the latest development version of this module, I've created a patch that will handled also the PUT requests.

skek’s picture

Removing the arguments after passing to $data because of duplications.

rumenyordanov’s picture

Adding unset of data if empty as it causes issues with some rest servers

rumenyordanov’s picture

Adding new patch as the last one was broken

  • dman committed 00af758 on 7.x-1.x authored by rumenyordanov
    Issue #2426053 by rumenyordanov, skek, hanoii: REST client should send...
dman’s picture

Status: Needs review » Fixed

Seems helpful and safe.
I can't test without a detailed use case that demonstrates PUT in action etc, but I don't see it breaking.

REPAIRED for code style and committed. Thanks folks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.