I have a REST method for search users. Right now I am having following signature for the REST method:
MyResponse GetUsers(UserSearchDTO search, int pageno, int totalrecords);
i.e it is accepting one object of UserSearchDTO, pageno and totalrecords param. The URL will look like
myapp/users?pageno={pageno}&totalrecords={totalrecords}
The end client will send "PUT" request for this service like:
myapp/users?pageno=1&totalrecords=10 and along with it it will pass xml data posted of UserSearchDTO like
<UserSearchDTO><Department>d</Department><Name>abc</Name></UserSearchDTO>
Is this a good architecture i.e in order to get users I am using "PUT" request type. The reason for doing this is because end client has to pass UserSearchDTO in xml form?
The other approach which I'm thinking is pure "GET" i.e instead of using UserSearchDTO I should have the following signature:
MyResponse GetUsers(string department,string name,...., int pageno, int totalrecords);
and the end client will call it like:
myapp/users?department=d&name=abc&......&pageno=1&totalrecords=10
I am in the process of writing my first REST service, so I am no expert, but in my opinion, I think it would be best to use a GET request, since that is exactly what you are doing -- getting data from the server. This will make it easier for other developers to support the app, instead of trying to figure out why you used PUT for a basic data retrieval.
If possible, I suggest that you try casting the UserSearchDTO XML as a string on the client and passing it to the GetUsers method as a string, then load the string into an XmlDocument() on the server and parse it into the DTO. Then your method signature would look like:
MyResponse GetUsers(string userSearchXmlString, int pageno, int totalrecords);
It looks like you're using WCF REST. With WCF REST, you have to implement the query mechanisms yourself as you are attempting to do. Have you considered using ASP.NET Web API? In Web API, your GetUsers() method simply needs to return an IQueryable<User> and Web API wraps that with OData querying capability which handles projection, filtering, sorting, aggregating and paging for you.
Related
I have an angular client and want to execute a get request to my web api backend to get a list of items from the underlying Dapper Db Wrapper. Dapper allows me to pass in parameters as an anonymous object which would in csharp look like this:
connection.GetList<T>(new {myParam1:"a", myParam2: true});
What I want to achieve is, to create this parameter object in my angular frontend and pass it in a post request to the server which would then pass it on to the GetList function. The problem here is that the web api does not deserialize it as an (anonymous) object, but rather and IEnumerable of JTokens?
My web api signature is this:
public async Task<IHttpActionResult> MyFunction([FromBody]dynamic whereCond)
I have also tried to pass the object as string wrapped in an outer object like so (angular client):
this.migController.MigrationGetMigrationReports({whereCond: JSON.stringify({NotMigrated: true, MissingTargetFiles: 0})})
and then on the server I manually deserialize it as JObject:
string obj = whereCond.whereCond;
dynamic pObj = JObject.Parse(obj);
But this results in the exact same result: pObj is an IEnumerable and therefore I get an error message from the GetList call:
An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context
can anybody help?
The answer to my question turned out rather simple:
dynamic pObj = JObject.Parse(obj).ToObject<ExpandoObject>();
I had to cast it as ExpandoObject not just dynamic.
#Tsahi: this is not a design problem. My intention was to provide the server with parameters (filter) which is a quite common task for a client to reduce the dataset to be transferred. We could debate a standard way how to provide these parameters, however. In my special case the most practical way is the anonymous object.
I am trying to send an array of items, whether that's a model[] of varying types or a string[]. From what I've looked at so far it doesn't seem possible, although we send arrays of models to the API controllers already using AJAX calls, this however needs to be sent from an App.
Currently I am sending one at a time to the server, I have tried using the [HtmlPost] tag as well as sending things via List, item[] and serialised as a string object (winds up too large easily).
//App Code
var data = MyListOfModels[];
var result = api.APIController.MyMethod(data);
//API Code
[Route("API/APIController/MyMethod")]
public bool MyMethod(Model[] modelList)
{
return service.DoSomethingWithModels(ModelList);
}
I'm expecting to be able to send an array to the method which can do something with that array of data.
The connections between the web API and Xamarin are built using Swagger.
I've been trying to figure this out for about a week now. It's time to ask S.O.
I have 4 overall goals here:
The controller code needs to use ViewModel request inputs for validation reasons. (Controller Snippet)
Client code for my API should use a nice model syntax. (Client Code Snippet)
For the swagger UI page, I would like the "Try me" interface to be usable. Either a bunch of text boxes, or a text area for a json blob to serialize and send over.
GET request
Client Code Snippet:
var response = client.GetUserProductHistory(new Models.UserProductHistoryRequest() {
Locale = "en-US",
UserPuid = "FooBar"
});
Controller Snippet
[HttpGet]
[HasPermission(Permissions.CanViewUserProductHistory)]
public JsonPayload<UserProductHistoryResponse> GetUserProductHistory([FromUri]UserProductHistoryRequest model)
{
JsonPayload<UserProductHistoryResponse> output = new JsonPayload<UserProductHistoryResponse>();
return output;
}
I have tried using [FromBody]. It looks great, but I get an error that says 'GET requests do not support FromBody'.
I tried using [FromUri], but then the generated client gives me like 15 method parameters per call in the generated client.
I tried using [FromUri], and operation filters so that the parameters would be condensed into Ref parameters (complex objects as defined by the spec). This actually worked decently for the client generation and the server side. Problem is, the UI for swagger looks really lame. A single TEXT box that you can't actually use very well. If I can figure out how to get the Swagger UI to change the appearance of the [FromUri] request to more closely match the [FromBody] UI, I will be in good shape here. Any ideas or pre-existing content that would point me in the right direction here?
Swagger is not the limitation - REST itself is. By definition of REST, web servers should ignore the incoming request body on all HTTP GET methods. ASP.NET enforces this convention, which is why you it doesn't allow you to use [FromBody] on the GET method.
When designing a REST API, the better practice is to use POST methods for an actual search. This will allow to use [FromBody], and as a bonus, Swagger will behave the way you want it to. See here for a supporting opinion: https://stackoverflow.com/a/18933902/66101
how do i pass two complex parameters, say two class objects, when i call HttpClient.GetAsync ?
I understand we could add it along the url if its simple parameters like string. But when it is complex ones such as class, how do we do it ?
use HttpClient.PostAsync
if you want to send complex data, and not just simple string
also on the server side, check if the api accepts post requests
you can test requests using http://Hurl.it
I have the following scenario.
There are few Events and each event is represented by group of friends.
1st i request a list of events which is achieved using simple Get request.
http://example.com:6400/api/Events/
Corresponding Rest API : public IEnumerable<Event> Get();
Now i can search the event list and can request for a particular event say (event 5)
http://example.com:6400/api/Events/eventdetail/5.
Corresponding Rest API : public HttpResponseMesssage eventdetail(int id);
But now if i want to receive info about a particular friend(say friend's id is 10) in that event(5) i am unable to find a way. One way i was able to achieve is using a comma separated
Get request:
http://example.com:6400/api/Events/eventdetail/5,10.
Corresponding Rest API: Not Sure ????
But i don't think this is the best way to do it. Is there any ways through which i can achieve the desired result and corresponding Rest API.
Just start accepting two parameters in your method:
public HttpResponseMesssage EventDetail(int id, int friendId) {
//Do your stuff!
}
The corresponding URI would look like:
http://example.com:6400/api/Events/EventDetail/5?friendId=10
Notice how the HTTP parameter name matches the C# method name. For more information about ASP.NET MVC routing I would suggest reading their overview.