Pass ID or Object which has irrelavant details as RequestBody in Rest Call? - rest

Approach 1:
#PostMapping("/api/{id}")
String getSomeObj(int id){
//make another rest call with id and get CustomObj
// then do some logic and return something
//Here response time will be more as it has again another rest calls
}
Approach 2:
#PostMapping("/api/{id}")
String getSomeObj(#PathParam("id") int id, #RequestBody CustomObj obj){
//directly do logic with the provided obj and return something
//Here Response time would be less as we are directly getting the actual Object from Request Body
//BUT is this a good practise to pass an object in which we need only few details?
}
Q1) All I am asking is to whether to pass just id or Object? If id is passed, another Rest call has to be made unnecessarily. If Object is passed, we can avoid making another rest call, BUT the problem is: this custom object may contain some irrelavant details too.. So, is this correct?
Q2) If passed with id, response time will be more when comparing with just passing object.. So, I am not understanding which approach should follow..

A1) This is all up to you and there is no "one correct" way. I would say if it's a small object pass the object and respond fast. If its a big object pass the id. How do you define big and small objects? if object has hashmaps or lists in it that's a big object. Also you can ignore serialization of internals; check https://www.baeldung.com/jackson-ignore-properties-on-serialization
A2) Pass the id and enjoy your REST service. After all REST is very fast. Don't worry about the speed of calls. If your back end function is fast and if you put a "loading" gif to front end; users will wait for the response.

Related

Multiple payloads in MVC core rest api

I am developing a rest api on .Net core 2.2 following MVC pattern.
I have a controller with a post method like this...
// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(string param, [FromBody] TodoItem item)
{
// some work...
return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}
And it works fine.
The customer asked to have an api on the same route, but the Json body could have 2 different structures, bearing the same data on different schemas.
I considered using
PostTodoItem(string param, [FromBody] Object item)
{
// TryCast item to one of the possible POCO classes then work with the correct one.
}
Do you know a better way, maybe with some advanced routing and filtering option?
This is not really possible nor desirable. Pretty much the core tenant of REST is a URI uniquely represents a particular resource. If you've got a URI like POST /todo, then the post body should be a "todo" and it should create a new "todo" based on that. Here, that is a TodoItem, so that is all that should ever be posted.
REST aside, this just won't work. When your action is activated, the modelbinder attempts to bind the post body to the param(s) that the action accepts. It basically just news up whatever type the param is, and then attempts to find something from the post body to bind to the various properties on that type. This is an intentionally simplistic description of what's happening; the important part is that the type of the param informs how the post body is bound. If you bind to an object (which has no members) or even a base type, then the only members of the post body that will be bound are those that are present on that type, not derived types thereof. Anything that cannot be bound is discarded.
Long and short, you need a unique route for each type of thing you're working with. Under the hood, you can share or otherwise reuse code by factoring out common functionality into private methods, employing inheritance, etc., but you need a distinct action and route to handle each case.

REST API to check if an object exists

I have currently a webservice that load an object which looks like /object/load?id=100, the problem is that my object is really huge and it takes a long time to get the full response of the webservice just to see if the object exists or not.
What is the best pratice here ?
Creating a new webservice /object/exists?id=100 thats only use HTTP status code (200 if object exists, 404 if not) ?
Add parameter to the /object/load webservice to return only simplified object ?
If you are only interested in existence, or knowing in advance how the API will respond if you do a real GET request, HTTP actually has a built-in method for that: HEAD.
I'd recommend creating a new method within your existing web service. Name that method 'Exists' or something similar, and make sure that it is a HttpGET method.
You could then pass in the ID of the object you want to check, then within the method just do a check to see if the object exists. If the object exists you should return true, else return false.

Is it better to use entity property vs assignments in http post controller?

So say we have an aspnet core2 controller that's returning HttpPost object from another app.
Im using Entity framework core and both ways work but I'm just curious into best practices and performance to know what to use?
[HttpPost]
public Message Post([FromBody] Message message)
{
// my old code
// var msg = new Message { Owner = message.Owner, Text = message.Text };
//db.Messages.AddAsync(msg)
var msgEntity = db.Messages.Add(message).Entity;
db.Messages.AddAsync(message);
db.SaveChangesAsync();
return message;
}
Something strange happens when I use Entity as well it changed the auto incremented Id parameter {Id:1002} when before I added it the next consecutive Id was suppose to be {Id:11}
You should never save anything from a request directly. There's your best practice. The previous code is superior for the sole reason that you're explicitly choosing what posted values are actually persisted, rather than just blindly saving anything a user decides to send directly to your database.
The even better approach is to actually use a view model to accept user input. For example:
public class MessageViewModel
{
public int OwnerId { get; set; }
[Required]
public string Text { get; set; }
}
Then, you accept this as a param, instead, and map it onto your entity:
public async Task<IActionResult> Post([FromBody]MessageViewModel model)
{
if (ModelState.IsValid)
{
var message = new Message
{
Owner = db.Users.Find(model.OwnerId),
Text = model.Text
};
db.Messages.Add(message);
await db.SaveChangesAsync();
return Ok(message);
}
return BadRequest(ModelState);
}
There's a number of important changes I made in the above code:
Added a conditional to check if ModelState.IsValid is true before proceeding with the save. As you have it now, you're just blindly attempting to save whatever gets passed in, even if doing so will end up raising a database exception because required values are missing and such.
With this conditional, you now need to handle the scenario where there's an issue. More likely than not, you'll want to return some sort of error object, to help the client fix issues. It's common to actually just return ModelState, which will serialize its list of validation errors, but you might want to do other things as well.
Since this now require potentially returning two different object types, the action signature has been changed to return IActionResult. It's usually better to just use this return type all the time. It's a catch-all, basically, whereas a specific return like Message can easily outgrow its usefulness, requiring you to just go ahead and change it later. You should really only return specific types when there's absolutely no chance of failure of any sort, i.e. the response will always be 200 OK. However, scenarios where that's the case are few and far between.
The view model just accepts the owner's id, instead of a full (presumably ApplicationUser) object. The same problem with accepting a Message and saving it directly exists here too. A malicious user could fudge with the Owner object properties, allowing them to potentially change all sorts of things that shouldn't be changed. In general, you should always set out to allow the user to manipulate as little data as possible. Anything you expose, should be done on purpose, fully understanding the implications. Since, we're now only accepting an id, we then need to look up the user with that id, to set the Owner property on the entity. If you happened to have an explicit foreign key property, such as OwnerId on Message, you could just set that directly.
Changed AddAsync to just Add. According to the documentation, you should almost never use AddAsync. It only exists for a very specific purpose that you're unlikely to ever encounter. It is recommend to always use Add, unless you have a good reason otherwise.
Added await to the SaveChangesAsync call. Always await asynchronous operations unless the completion of the operation as no bearing on anything. Here that's definitely not the case. SaveChangesAsync can raise exceptions, exceptions that your application will need to handle. Not awaiting it, basically just swallows these and lets the code happily continue as if there was no issue. Although that may sound like a positive, it is definitely not. There's also other issues that can be caused by not awaiting, such as the context may end up getting disposed before the call finishes.
Since we're now awaiting SaveChangesAsync, async must be added to the method signature, and you must return a Task<IActionResult>.

Working with Backbone Events to trigger post with different methods appended to Collections URL

I am working with a handful of RESTFul API's that are as follows in concept.
domain.com/api/?id=xxxxx as the getter API call for the model/collection
In this case for me though there is several POST based setters that look like.
domain.com/api/start?id=xxxxx
domain.com/api/stop?id=xxxxx
domain.com/api/method?id=xxxxx
domain.com/api/thing1?id=xxxxx
domain.com/api/thing2?id=xxxxx
So I am trying to figure out how to trigger a POST based on the collection/model URL but appending start, stop, method, thing1, thing2 to it.. along with the id= as depicted.

Using different delegates for NSXmlParser

I am trying to figure out the best way to design something. I am writing an iPhone App and for the most part I am using async calls to a web service. This means that I cam setting up a URLConnection, calling start and letting it call me back when the data is available or an exception occurs. This works well and I think is the correct way to handle things.
For example:
I request a list of people from a web service. The resulting list is Xml Person elements which will be translated into an objective-c "Person" object by my XmlDelegate.
When I call the function to get the person, I pass in a "PersonResultDelegate", which is a protocol with a single function called "PersonReceived:(Person *)p". So, each time I get a complete Person object, I call that method and all is well. So, my detail view (or search result view) just receives the elements as they are available.
The problem comes when I need to obtain more then one specific object. In my specific case, I need to get the first and last appointment for a person. So, I need to make two API calls to obtain these two single Appointment objects. Each Appointment object will result in a call to the registered AppointmentResultDelegate, but how will I know which is the first and which is the last? I also need to somehow handle the case when there is no "first" or "last" Appointments and the Delegate will never get called.
What would be the correct way design wise to handle this? Should I add some additional context information to the initial request which is passed back to the handle in the delegate? An opaque piece of data which only makes sense to the person who made the initial call? What are my other options?
Solution
What I actually ended up doing is just passing an opaque piece of data along with the Appointment to the delegate. So, when I request an appointment object I have a method like:
getNextAppointment withDelegate:self withContext:#"next"
getPrevAppointment withDelegate:self withContext:#"prev"
This way when the delegate gets called I know what appointment is being delivered.
"Each Appointment object will result in a call to the registered AppointmentResultDelegate, but how will I know which is the first and which is the last?"
By looking at the order in which you receive these callbacks. Or by looking at some value in that xml data. Like a sequence or data. I don't know your data of course.