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:
Serializing the params into one single JSON string and picking it apart in the API. http://forums.asp.net/t/1807316.aspx/1 Pass the params in the query string. What is best way to pass multiple query parameters to a restful api? Defining the params in the route: api/controller/date1/date2 Using a POST that inherently lets me pass an object with params. 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?
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.
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
api/controller?start=date1&end=date2
style URI.
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...
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
}
}
Get
), can you still use [FromUri]
? I can't seem to get that to work.
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.
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
Use Parameter Binding as describe completely here : http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
[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
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"
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
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");
}
}
}
This code works for me. Then I can use the regular querystring on the url http://.../api/GetSomething?paramOne=1¶mTwo=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}")]
Success story sharing
WebApiConfig
file, but this is indeed nicer.Route
for named parameters (e.g. query parameters)?