4

For RESTful APIs, I need to use get for retrieving a list, however I want to pass some the following complex parameter as an input for the method.

{
  "Filters": [
    {
      "FieldName": "sample string 1",
      "FieldValue": "sample string 2"
    },
    {
      "FieldName": "sample string 1",
      "FieldValue": "sample string 2"
    }
  ],
  "SortField": "sample string 1",
  "SortValue": 0,
  "Page": 2,
  "PageSize": 3
}

How the parameter will be passed since I cannot use the RequestBody in a Get method, and if I make it Post, it won't be RESTful.

karel
  • 5,489
  • 46
  • 45
  • 50
Homam
  • 23,263
  • 32
  • 111
  • 187
  • There is another problem with not using url-encoded query, it is not easy(possible?) to return 'next' link in response. – wondra Dec 17 '19 at 13:09

4 Answers4

5

Reading REST API using POST instead of GET and others, it doesn't seem that there is a canonical definition of Restful that forbids using POST for what you want.

In this case the rule could be "do what's best".

Further, since it appears that you own both the host and client ends of the process, there's not much reason to avoid POST.

Fundamentally, there's no simple way to incorporate serialized json in a URL, which is what GET would need.

Community
  • 1
  • 1
dkretz
  • 37,399
  • 13
  • 80
  • 138
  • My controller enable CRUD operation which uses Post method for Create and Get to retrieve data. However, for this method, I should use a custom Post method – Homam May 10 '16 at 17:25
4

I am totally against the use of serialized JSON inside the query string of a URI, for several reasons:

  1. It makes the URI not human-readable (encoded brackets and whitespaces generates horrible query strings)
  2. It makes the parameter not composable (to add another "filter" you'll have to unencode the JSON, deserialize it into an object, add the new field, and then again serialize + encode)
  3. It creates long URIs for no benefit (again, encoded parts of your JSON unnecessary make the query string grow)

Even if you could use POST for such a purpose, I believe it would be semantically more correct to keep using GET if you intend to only query data, without modifying it.

In many situations like the one you described I simply converted my complex object to separated query string parameters, creating URIs like this one:

http://myhost.com/query?filters.fieldName1=fieldValue1&filters.fieldName2=fieldValue2&sort=fieldName&sortDirection=asc&page=2&pageSize=3

You may easily parse this query string in ASP.NET Web Api 2 (I suppose you are using this framework because of the tag inside your question) using a custom ModelBinder for a custom Paging object that contains any data you require to execute your query server-side.

As an alternative approach you could consider putting those parameters inside a custom (or multiple) request header, and then read them server-side:

X-Query-Filter: FieldName1=FieldValue1&FieldName2=FieldValue2
X-Query-Sort: FieldName
X-Query-Sort-Direction: ASC
X-Query-Page: 2
X-Query-PageSize: 3
Federico Dipuma
  • 17,655
  • 4
  • 39
  • 56
1

pass the filters in the URI:

 var encodedQueryString = encodeURIComponent(JSON.stringify({
      "Filters": [
        {
          "FieldName": "sample string 1",
          "FieldValue": "sample string 2"
        },
        {
          "FieldName": "sample string 1",
          "FieldValue": "sample string 2"
        }
      ],
      "SortField": "sample string 1",
      "SortValue": 0,
      "Page": 2,
      "PageSize": 3
    }))
    var url = example.com?filters="+encodedQueryString
    //http://www.example.com?filters=%7B%22Filters%22%3A%5B%7B%22FieldName%22%3A%22sample%20string%201%22%2C%22FieldValue%22%3A%22sample%20string%202%22%7D%2C%7B%22FieldName%22%3A%22sample%20string%201%22%2C%22FieldValue%22%3A%22sample%20string%202%22%7D%5D%2C%22SortField%22%3A%22sample%20string%201%22%2C%22SortValue%22%3A0%2C%22Page%22%3A2%2C%22PageSize%22%3A3%7D

Fiddler output:

enter image description here

Scott Weaver
  • 7,192
  • 2
  • 31
  • 43
  • well, I don't know your exact scenario, so no, but it did seem to validate as a legit URL: http://www.freeformatter.com/url-parser-query-string-splitter.html – Scott Weaver May 10 '16 at 17:44
  • The problem is you did not give a name for the parameter. `?filters={encoded string}` would allow the endpoint to read the string and then deserialize into an object. – Dan Harms May 10 '16 at 18:13
1

Where complex payloads would exceed the size possible for url parameters, you can POST the large payload to a queries endpoint and then use an URI for that as a parameter in a GET call.

It's two calls and not one, but in a purist sense allows for binaries and blobs to be use in GET calls. I think it's overkill except for special cases.

If POST works, use it.

JSDBroughton
  • 3,966
  • 4
  • 32
  • 52