How should I pass multiple parameters to an ASP.Net Web API GET?

The Question :

137 people think this question is useful

I am using the .Net MVC4 Web API to (hopefully) implement a RESTful api. I need to pass in a few parameters to the system and have it perform some action, then return a list of objects as the results. Specifically I am passing in two dates and returning records that fall between them. I’m also keeping track of the records returned so that subsequent calls do not get reprocessed in the system.

I’ve considered a few approaches:

  1. Serializing the params into one single JSON string and picking it apart in the API. http://forums.asp.net/t/1807316.aspx/1

  2. Pass the params in the query string.
    What is best way to pass multiple query parameters to a restful api?

  3. Defining the params in the route: api/controller/date1/date2

  4. Using a POST that inherently lets me pass an object with params.

  5. Researching ODATA since the Web API (currently) supports it. I haven’t done much with this yet so I’m not very familiar with it.

It seems that proper REST practices indicate when data is pulled, you should use a GET. However, GET should also be nullipotent (produces no side-effects), and I wonder if my specific implementation violates that since I mark records in the API system, hence I am producing side-effects.

It also led me to the question of supporting variable parameters. If the input parameter list changes, it would be tedious to have to re-define your route for Choice 3 if that happens a lot. And what might happen if the parameters are defined at run-time…

In any case, for my specific implementation, which choice (if any) seems best?

The Question Comments :

The Answer 1

10 people think this answer is useful

What does this record marking mean? If this is used only for logging purposes, I would use GET and disable all caching, since you want to log every query for this resources. If record marking has another purpose, POST is the way to go. User should know, that his actions effect the system and POST method is a warning.

The Answer 2

144 people think this answer is useful

I think the easiest way is to simply use AttributeRouting.

It’s obvious within your controller, why would you want this in your Global WebApiConfig file?

Example:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

The {} names need to match your parameters.

Simple as that, now you have a separate GET that handles multiple params in this instance.

The Answer 3

49 people think this answer is useful

Just add a new route to the WebApiConfig entries.

For instance, to call:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

add:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Then add the parameters to the HTTP call:

GET //<service address>/Api/Data/2/10 

The Answer 4

45 people think this answer is useful

I just had to implement a RESTfull api where I need to pass parameters. I did this by passing the parameters in the query string in the same style as described by Mark’s first example “api/controller?start=date1&end=date2”

In the controller I used a tip from URL split in C#?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

In my case I was calling the WebApi via Ajax looking like:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

I hope this helps…

The Answer 5

38 people think this answer is useful

I found exellent solution on http://habrahabr.ru/post/164945/

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

The Answer 6

8 people think this answer is useful

Using GET or POST is clearly explained by @LukLed. Regarding the ways you can pass the parameters I would suggest going with the second approach (I don’t know much about ODATA either).

1.Serializing the params into one single JSON string and picking it apart in the API. http://forums.asp.net/t/1807316.aspx/1

This is not user friendly and SEO friendly

2.Pass the params in the query string. What is best way to pass multiple query parameters to a restful api?

This is the usual preferable approach.

3.Defining the params in the route: api/controller/date1/date2

This is definitely not a good approach. This makes feel some one date2 is a sub resource of date1 and that is not the case. Both the date1 and date2 are query parameters and comes in the same level.

In simple case I would suggest an URI like this,

api/controller?start=date1&amp;end=date2

But I personally like the below URI pattern but in this case we have to write some custom code to map the parameters.

api/controller/date1,date2

The Answer 7

8 people think this answer is useful

Use Parameter Binding as describe completely here : http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

The Answer 8

4 people think this answer is useful
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Both params of the root link({one},{two}) and Get function parameters (one, two) should be same

The Answer 9

2 people think this answer is useful

I know this is really old, but I wanted the same thing recently and here’s what I found…

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" &amp;&amp; test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }


So now in your address/URI/…

http(s)://myURL/api/myController/?var=getnew&test=test

Result: “Found Test”


http(s)://myURL/api/myController/?var=getnew&test=anything

Result: “Couldn’t Find that test”

The Answer 10

2 people think this answer is useful

Now you can do this by simply using

        public string Get(int id, int abc)
        {
            return "value: " + id + "  " + abc;
        }

this will return: “value: 5 10”

if you call it with https://yourdomain/api/yourcontroller?id=5&abc=10

The Answer 11

0 people think this answer is useful
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id &amp;&amp; e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }

Add a Comment