sig606
sig606

Reputation: 1866

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

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?

Upvotes: 146

Views: 391187

Answers (12)

Sinji Yang
Sinji Yang

Reputation: 129

This code works for me. Then I can use the regular querystring on the url http://.../api/GetSomething?paramOne=1&paramTwo=2

.NET 6 Core

[Route("api/GetSomething")]
public IActionResult GetSomething(int paramOne, int paramTwo)
{
    ...    
    return Content(jsonData);
}

instead of doing the following [Route("api/GetSomething/{paramOne}/{paramTwo}")]

Upvotes: 0

RaZor1994
RaZor1994

Reputation: 105

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

Upvotes: 2

Rick Riggs
Rick Riggs

Reputation: 336

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" && 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"

Upvotes: 2

Jesse Mwangi
Jesse Mwangi

Reputation: 155

    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 && 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");
            }
        }
    }

Upvotes: 0

LukLed
LukLed

Reputation: 31842

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.

Upvotes: 11

ashwath hegde
ashwath hegde

Reputation: 656

 [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

Upvotes: 4

Mark Pieszak - Trilon.io
Mark Pieszak - Trilon.io

Reputation: 66971

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.

Upvotes: 155

danan
danan

Reputation: 451

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

Upvotes: 8

Andrew Veriga
Andrew Veriga

Reputation: 776

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

Upvotes: 41

Graham Wright
Graham Wright

Reputation: 646

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 

Upvotes: 51

Nigel Findlater
Nigel Findlater

Reputation: 1724

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

Upvotes: 45

VJAI
VJAI

Reputation: 32758

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

Upvotes: 9

Related Questions