Web API ignores non-model body parameters; should throw error - asp.net-web-api

In Web API v2 when you supply data in the POST body that are not part of the model, they are ignored by the framework. This is fine in most cases, but I need to check this and return an error response, so the user doesn't get unexpected results (he expects these wrong parameters to do something...).
So how do I check for this? The model will be null, but when the framework has parsed the data and returned a null-model, I can no longer access the body through Request.Content. So what options are there?

One way is to derive your DTO class from DynamicObject. Check out my blog post: http://lbadri.wordpress.com/2014/01/28/detecting-extra-fields-in-asp-net-web-api-request/

Related

Correct way to return REST Api response

I am developing a REST API for a website, let's say i have a POST endpoint('/users/create') which i want to create the user if they don't already exist and return the user as a result.
What this would look like is:
#PostMapping(value = "/users/create")
public User createUser(#RequestBody UserDTO form)
The problem with this is that when the user is successfully created there is no problem just returning the user with a response code 200. The problem comes when I am doing input validation and for example a user with that email already exists and i want to return user: null and some sort of message as to what specifically failed in the user creation. I've thought about multiple posibilities such as creating a custom object that has fields for both an object of any type ( user in this case ) and a message along with it, as well as using HttpServletResponse / ResponseEntity. They all seem like they are overcomplicating something that should be realtively simple in my eyes and i don't know which approach is the best. First time posting so excuse me if i'm a bit all over the place.
there probaly is an solution which uses the Http error system but as an alternative I would use an if statement on both sides, which checks if the user already exists and if it does it sends user:error or something like that. The client side then has to check if the anwser is a user or error and if it is error a pre programmed message is shown

How to inject a header from the errormessage

I've been attempting to inject a custom header for a error response status (and failing).
I have a very simple lambda being used
exports.handler = (event, context, callback) => {
// TODO implement
//callback(null, 'Hello from Lambda');
var error = {
name:"error",
message:"I am a failure",
statusCode: 400
};
error["x-test"] = 'foo';
callback(JSON.stringify(error), null);
};
In the api gateway, I've done the following:
set up CORS to include x-test
responsetemplate = "$input.path('$.errorMessage')"
responseparameter to include:
method.response.header.x-test = integration.response.body.x-test
Also, I have a statusCode mapped using '.*statusCode.*?400.*'
This has turned out empty.
so I decided to take a step back and see what happens if I do:
method.response.header.x-test = integration.response.body
I found that I get the stringified response of errorMessage.
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
So I decided to change the responsetemplate to force it to json by doing the following:
responsetemplate = "$util.parseJson($input.path('$.errorMessage'))"
and I still get the stringified response:
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
My guess is that it doesn't transform as expected, but only for the final output.
So how would you take a value and shove it into a header?
Thanks,
Kelly
I think this is more of a design choice regarding the limitation imposed by both Lambda and APIGateway. I will try my best to walk through my thoughts.
First of all, in Lambda, callback(error, result) function can either take an error string as first argument, or an object as result response. If you want to pass along a simple error message, you could definitely just do that. However, in your case, as you tried to pass along an entire error object, choosing the second option is clearly a better solution (in contrast to stringifying an object and parse it into object again). As a result, the final line of your Lambda function should be:
callback(null, error);
Yes, in this case, if you test your function in Lambda, the output result will no longer be red and flag it as an error, but this won't matter as you can format your headers and response in APIGateway.
Now you need to set things up in APIGateway, in which you need to make use of the object passed by Lambda.
It's actually rather easy to use method execution interface to configure headers.
In Method Response, you need to add the headers you want to include in the response for a specific status code, which in your case is x-test. (If you want the API to return different status codes, you can also configure that in this panel.)
Then go to Integration Response, under the same status code, you will see the added header available. According to this documentation from AWS, you can use integration.response.body.JSONPath_EXPRESSION to assign the header value (this is another reason that you should return object rather than string in Lambda, as there is no formal API to parse object from string at this stage). This time, as your Lambda is passing an object, the value of x-test header is:
integration.response.body['x-test']
Now your API should have the proper header included.
NOTE: In order to set up different status code in APIGateway, you should leave some distinguishable data fields (your statusCode: 400 should work perfectly) in you response body, so you can use RegEx to match those fields to a specific status code.
So... above doesn't work with success message. I found this blog though talking about error handling design pattern. Apparently what they suggest is only mapping status code when there is an error, in which case no body should be passed (only the errorMessage), as browser won't care about response body for a status code other than 200 anyway.
I guess after all, it is impossible to customize both status code and header at the same time with Lambda passing an object to APIGateway?
This is due to the fact that you are stringifying the error object coming from your Lambda function. API Gateway attempts to resolve the JSON-Path expression and can't evaluate "x-test" in a string. If you return an object instead of a string, this should work.
You may want to consider using proxy integrations which allow you to control the headers and status directly from your Lambda function.
Update: I've written a blog post on this topic with sample code # https://rpgreen.wordpress.com/2017/01/25/how-to-send-response-headers-for-aws-lambda-function-exceptions-in-api-gateway/

Writing data to model from POST request (Odoo 9.0)

I have the following model:
class LibraryBook(models.Model):
_name = 'library.book'
name = fields.Char('Title', required=True)
date_release = fields.Date("Release Date")
author_ids = fields.Many2many("res.partner", string="Authors")
I'm new to Odoo and trying to understand the basics of how to save data to my model from a POST request like the following
curl -i -X POST --data "name=Odoo%20-%20Much%20Mystery,%20Wow&author_id=Doge" http://0.0.0.0:8069/test
I found a way doing this by setting the csrf parameter in my controller to false like so:
[...]
#http.route('/test', type='http', auth='public',methods=['POST'], website=True, csrf=False)
def test(self, **kwargs):
record = request.env['library.book'].sudo()
record.create(kwargs)
I'm wondering now if there is a way to avoid setting csrf=false since I've read that it's a bad idea to do so in general. Also, what would I need to get rid of that .sudo()? Not setting csrf=false leads to a 400 BAD REQUEST with Invalid CSRF token. Removing sudo() leads to a 500 INTERNAL SERVER ERROR. In Odoo Development Cookbook it says in one example with auth='none'
Lack of a user is also why we have to sudo() all our calls to model methods in the example code
Assuming I would expect a POST request from an API, is it possible to associate it with a user so I don't have to sudo()?
I would very much appreciate any clarification on this.
UPDATE
So I just found this (line 817):
if the form is accessed by an external third party (e.g. REST API endpoint, payment gateway callback) you will need to disable CSRF
protection (and implement your own protection if necessary) by
passing the csrf=False parameter to the route decorator.
which I guess leaves only one question open, regarding sudo.
SUDO()
creates a new environment with the provided user set, uses the administrator if none is provided (to bypass access rights/rules in safe contexts), returns a copy of the recordset it is called on using the new environment:
Odoo does not allow public users to create, update, delete a record.
If we want to create a record from the public users then we need to create a record with the sudo().
Create record object as administrator
request.env['library.book'].sudo().create(vals)
I hope this may help you.
for more information you can navigate to following links :
https://www.odoo.com/documentation/9.0/reference/orm.html
Thanks

Angular $http.delete request with body

So I looked at this post:
is an entity body allowed for an http delete request
Which seems to indicate that while it is 'ok' to do on some conceptual level, in practice it may not be doable because browsers just ignore it.
I have some express.js authentication middleware I need to get through, and I don't want to attach my user details to url params. All my other requests that need to authenticate attach these details to the body of the request.
Is there some way to force this? I saw some other posts where some people seemed to have success in passing a body with their delete request.
I am running a node/sails back-end. It always logs the body as undefined for a delete request. Is there any way to modify
The sails API pulls the id of the object to delete from the params, so we have to append the id to the url.
But if I want to pass some authentication details in a body for server-side verification before processing the delete request, I can't just stick them in an object as the second parameter of the delete request, like you can with $http.post.
Angular's post method automatically assigns whatever we insert as a second parameter to the body of the request, but the delete method does not.
Angular's $http.delete method does allow us to supply a config object as the second parameter, through which we can get access to the 'data' property. This is the same way post does it through it's second parameter.
So if we need to attach a body to a delete request we can use the following:
$http.delete('/api/' + objectToDelete.id, {data: {id: currentUser().id, level: currentUser().level}});
This will pass the object to delete's id in the url parameter, and my user credentials in the body as an object.
Honestly, everytime a trouble sounds like a "restriction of as REST", a rethink of the strategy and the philosophy might be a good idea.
I have some authentication middleware I need to get through
I don't want to attach my user details to url params
I'm not directly answering the question, but you should know that among the commons
URL parameters (or query, but URL anyway)
Body
there is a third option for "passing values to the server" :
request Headers
I'd just suggest to consider that third option to provide your credentials: request header.
Edit : following appendix would just apply to any "external" middleware, like a proxy server or whatever, not a true express middleware inside sails.js
In addition, that would be a good idea that your middleware stripped those headers before redirecting to the real action.

ASP .NET Web API Post modelbinding issues

I am a web API newbie, trying my first POST to the API (all my GETs are fine). And no matter what I try, model binding doesn't seem to work. Routing is fine, because I see control coming to the correct method, but model object references is always null. I tried with a simple class as model (two properties, both strings), still no luck.
Any suggestions on what I am missing? I am using fiddler to post. eg: request body has
{"Name":"Test","Description":"Test"}
Tried with a = at the start, Tried method-argument-variable= at the start, no luck.
null always.
When you sending the parameter by request body , you must use the [FromBody] attribute in method body. [FromBody] denotes it binds the parameters from request to the model class.
Check whether you are using [FromBody] or by url ?
[System.Web.Http.HttpPost]
public List<PortalUser> GetPortalUsers([FromBody]PortalUser PortalUser)
{ }

Resources