Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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?

share|improve this question
up vote 6 down vote accepted

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 this record marking is has another purpose, POST is the way to go. User should know, that his actions affect system and POST method is a warning.

share|improve this answer
    
By marking I mean simply tracking which records are processed and returned so that subsequent calls don't repeat them. In my case I'm just making an insert into another table to track which are processed. – sig606 Jun 8 '12 at 16:40
    
Right now I do have it implemented as a POST mainly for the reason you said--actions happen and the consumer is aware of them. Plus it seems easy and most flexible with resp to passing different data in. – sig606 Jun 8 '12 at 16:41
    
@sig606: POST is the way to go for me, but your protocol doesn't seem to be safe. What if something happens and records are retrieved on client side, but not processed due to a bug? You won't return them any more and client is left with lost data. – LukLed Jun 8 '12 at 16:43
    
Right now my API only returns records after they were processed. So the consumer passes the API two dates. Records between those two dates are processed and marked. Then the data is returned to the caller. I suppose if something happens during the processing or after processing before reaching the client, I have a problem. – sig606 Jun 11 '12 at 0:55

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.

share|improve this answer
7  
This is great. Most people recommend setting up the route in the WebApiConfig file, but this is indeed nicer. – rhyek Jun 20 '15 at 4:26
2  
Indeed, we (most people) do recommend having a centralized management area for your config. In the case of Web APIs (Microsoft or otherwise), centralized patterns for REST are key. Attribute routing is cute, but it makes one-off exceptions far too tempting. – David Betz Oct 19 '15 at 2:32
1  
Agreed, I need to update my answer actually. There's a much better way of doing multiple parameters with GETs. Posted this when I was newer to WebAPI, now I don't use AttributeRouting (unless I just don't want to create a new Controller), and pass all the Parameters in the QueryString, they map automatically. Updating when I get a chance so people don't use this older method – Mark Pieszak Oct 19 '15 at 14:20
    
Is there a way to set a Route for named parameters (e.g. query parameters)? – Shimmy Dec 16 '15 at 5:00
    
Yay found it right here – Shimmy Dec 16 '15 at 5:01

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 
share|improve this answer
5  
This seems to be the only answer that lists all the parts. I wish that someone better described how to use the api/controller?start=date1&end=date2 style URI. – Hot Licks May 22 '14 at 20:29
    
@Hot Licks Andrew Veriga's answer works well with query string arguments. Essentially, you bind the query string names to class properties and pass them into your method. Your method will take a single class argument marked with the [FromUri] attribute and will have your query string arguments as its properties. – David Peterson Oct 11 '16 at 20:05

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...

share|improve this answer
2  
I guess you're not using WebApi because ParameterBinding will map your querystring to your api method parameters automagically... – emp Apr 29 '14 at 13:20
1  
Yes, a better way would be to use and attribute like [Route("api/DbMetaData/{system}/{searchString}")] and then add there paramters to the Get(string system, string searchString) and then call with "...api/DbMetaData/mysystem/mysearchstring" – Nigel Findlater May 9 '14 at 9:25

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
    }
}
share|improve this answer
1  
The clue here is the [FromUri] – tranceporter Sep 23 '15 at 9:28
1  
Though the article is in Russian, @tranceporter is right. The "FromUri" looks like a great way to get the parameters from the url. Another article that might be helpful: asp.net/web-api/overview/formats-and-model-binding/… – Greg B Dec 17 '15 at 18:41
    
This is what I've been doing for quite a while now and it's worked great! I'd also recommend this solution. – David Peterson Oct 11 '16 at 20:00
    
If you call into another helper method (not the Get), can you still use [FromUri]? I can't seem to get that to work. – jocull Nov 10 '16 at 20:21

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&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
share|improve this answer
    
Actually, those were my orig explanations. I think LukLed shined up my tags and URL link. – sig606 Jun 8 '12 at 16:43
    
As far as SEO, in this case it wouldn't apply. This code will be "server-to-server", so I wouldn't care if the outside world ever discovered it. In fact, I have to make sure proper security steps are taken to avoid random access. I've had to do the JSON serialization for another part of the system (seems to be a bug trying to POST large lists of obj so I had to serialize to string), so it wouldn't be much of a stretch in this case. – sig606 Jun 8 '12 at 16:46
1  
I hope you already have answers then why you are asking question? – VJAI Jun 8 '12 at 17:17
2  
Sorry for this late response, Mark. I had tried a few solutions but wasn't sure which was the best and was trying to stick with industry-standard approaches, so I posted here at SO. – sig606 Jun 22 '12 at 15:55
1  
@Mark Something like to the next: stackoverflow.com/questions/9681658/…? – RredCat May 7 '13 at 8:57

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.