Homam
Homam

Reputation: 23841

How to use complex parameters with Web API RESTful Get method

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.

Upvotes: 4

Views: 10942

Answers (4)

Federico Dipuma
Federico Dipuma

Reputation: 18265

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

Upvotes: 4

JSDBroughton
JSDBroughton

Reputation: 4034

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.

Upvotes: 1

Scott Weaver
Scott Weaver

Reputation: 7351

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

Upvotes: 1

dkretz
dkretz

Reputation: 37645

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.

Upvotes: 6

Related Questions