How to localize exception message for Json deserialization? An invalid parameter was passed when requesting the interface? - exception

My development environment is.Net7 WebApi (out of the box)
Below is the relevant code. DataAnnotations I have implemented localization.
using System.ComponentModel.DataAnnotations;
namespace WebApi.Dtos
{
public class UserRegistrationDto
{
[Required(ErrorMessage = "UserNameRequiredError")]
[MinLength(6, ErrorMessage = "UserNameMinLengthError")]
[MaxLength(30, ErrorMessage = "UserNameMaxLengthError")]
public required string UserName { get; set; }
[Required(ErrorMessage = "PasswordRequiredError")]
public required string Password { get; set; }
}
}
[HttpPost]
public async Task<IActionResult> RegisterUser([FromBody] UserRegistrationDto userRegistration)
{
return Ok(1);
// IdentityResult userResult = await _userManager.CreateAsync(new IdentityUser { UserName = userRegistration.UserName }, userRegistration.Password);
// return userResult.Succeeded ? StatusCode(201) : BadRequest(userResult);
}
When the request body is invalid JSON.
curl -X 'POST' \
'https://localhost:7177/Authenticate/RegisterUser' \
-H 'accept: */*' \
-H 'Api-Version: 1.0' \
-H 'Content-Type: application/json' \
-d '{}'
{
"$": [
"JSON deserialization for type 'WebApi.Dtos.UserRegistrationDto' was missing required properties, including the following: userName, password"
],
"userRegistration": [
"The userRegistration field is required."
]
}
When the request body is Empty.
curl -X 'POST' \
'https://localhost:7177/Authenticate/RegisterUser' \
-H 'accept: */*' \
-H 'Api-Version: 1.0' \
-H 'Content-Type: application/json' \
-d ''
{
"": [
"The userRegistration field is required."
]
}
It throws exception information before binding to DTO, can this exception information be localized? If not, is it possible to capture this information for secondary processing, such as returning a fixed JSON format?
I've tried this in the Program.cs entry file, but it's not ideal.
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = false;
options.InvalidModelStateResponseFactory = context =>
{
bool knownExceptions = context.ModelState.Values.SelectMany(x => x.Errors).Where(x => x.Exception is JsonException || (x.Exception is null && String.IsNullOrWhiteSpace(x.ErrorMessage) == false)).Count() > 0;
if (knownExceptions)
{
return new BadRequestObjectResult(new { state = false, message = localizer["InvalidParameterError"].Value });
}
// ...
return new BadRequestObjectResult(context.ModelState);
};
})
I have also tried this method, but I can’t capture the exception information that failed when binding DTO alone. They will appear together with the ErrorMessage exception information in DTO like the above writing method.
.AddControllers(options =>
{
// options.Filters.Add(...);
// options.ModelBindingMessageProvider // This doesn't work either, it seems to support [FromForm]
})
Back to the topic, can it be localized? Or there is something wrong with the code. I just learned .Net not long ago. Most of the information I learned came from search engines and official documents. Thanks in advance.

Use the following method.
.AddControllers(options =>
{
// options.ModelBindingMessageProvider.Set...
})
It seems that the exception of JSON deserialization caused by passing invalid parameters can only be eliminated on the client side. So far it seems I haven't found a localization for this exception, but it's not very important to me at the moment.
Thanks #XinranShen for helping point me in the right direction.

Related

How can I property output for application/x-ndjson

#GetMapping(produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_NDJSON_VALUE
})
public Flux<Some> read() {
}
When I curl with --header 'Accept: application/x-ndjson'
The outer array is gone but all new lines in each elements is not gone.
{
"some": "thing"
}
{
"some": "other"
}
How can I make them as single-line as possible?

laravel 5.6 with MySql gives Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException error

There are similar questions under this topic, but none of them gave me an answer. I'm a beginner to laravel and trying to learn by myself.
When I try to connect laravel (version 5.6) with MySql it gives this error.
These are the code lines that working with.
CameraController.php
<?php
namespace App\Http\Controllers;
use App\Camera;
use Illuminate\Http\Request;
class CameraController extends Controller{
public function postCamera(Request $request){
$camera = new Camera();
$camera->email = $request->input('email');
$camera->password = $request->input('password');
$camera->save();
return response()->json([
'message'=>$camera
]);
}
}
CreateCamreasTable.php
public function up(){
Schema::create('cameras', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->text('email');
$table->text('password');
});
}
api.php
Route::post('/addCamera', ['as' => 'Camera', 'uses' => 'CameraController#postCamera']);
user.php
class User extends Authenticatable{
use Notifiable;
protected $fillable = [
'email',
];
protected $hidden = [
'password',
];
}
I couldn't found out what's wrong with my code..
PS- I'm trying with postman app that supports with sending requests and reading responses. what I'm sending is a json object
{
"email" : "rr#gmal.com",
"password" : "fjf"
}
The error that I receive is

custum error reponse in json format in symfony

i try to read a json data , so when the response with status ok (200) i can get data correctly in json format , but the webservice return a message if there is no item to return so he generate a message like that :
{"message " : "item not found" }
the problem is when symfony find that the response it not found he throw an exception not found while i want to just return the message that the webservice provide .
this is my controller code:
/**
*
* #Get("/getUserByUid/{uid}")
*/
public function getUserByUidAction($uid)
{
$url = self::Ws_URL . self::Ws_PORT . self::Ws_GetUserByUID . $uid;
$headers = array() ;
$headers[] = "auth_token: ".self::Ws_Token ;
$headers[] = "Content-Type: application/json" ;
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
"http" =>array(
"method" => "GET",
"header" => "auth_token: ".self::Ws_Token
)
);
$response = file_get_contents($url, true, stream_context_create($arrContextOptions));
return New Response($response) ;
}
If the web service is RESTFull then return a http code 404 with the above message {"message " : "item not found" }, then file_get_contents does not fetch the content of the file because the 404 is saying Does not exist. To get the full response and http code use curl instead.

In Symfony2, is there a way to pretty-print JSON responses?

I am writing a REST API in Symfony2, and I have my controller outputting JSON responses using the provided JsonResponse class:
$response = new JsonResponse(null, $status);
$response->setData($node['Content']);
return $response;
However, for debugging purposes, it would be nice to be able to pretty print the output. Is there an argument I can pass to the JsonResponse object to enable pretty-printing of the output?
Creating an event listener for that, as in Pawel's answer is overengineering.
To prettify, you just pass in the JSON_PRETTY_PRINT constant to the JsonResponse via the setEncodingOptions, like in this example:
$response = new JsonResponse( [ 'your' => 'data' ] );
$response->setEncodingOptions( $response->getEncodingOptions() | JSON_PRETTY_PRINT );
return $response;
You can see the Symfony API for more information:
Class JsonResponse:
http://api.symfony.com/3.2/Symfony/Component/HttpFoundation/JsonResponse.html
Method setEncodingOptions:
http://api.symfony.com/3.2/Symfony/Component/HttpFoundation/JsonResponse.html#method_setEncodingOptions
This is documentation for v3.2... but older versions like for example v2.7 also have this method.
You can create EventListener for that. Here is mine
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Preetify json response.
*/
class FormatJsonResponseListener
{
public function onResponse(FilterResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if (APPLICATION_ENV === 'development' || APPLICATION_ENV === 'dev' || $request->query->get('pretty_json', false) == true) {
$response = $event->getResponse();
$responseData = $event->getResponse()->getContent();
$response->setContent(Json::indent($responseData));
$event->setResponse($response);
}
}
}
And register that service with:
#services.ym
services:
your.service.listener.format_json:
class: Your\Vendor\FormatJsonResponseListener
tags:
- { name: kernel.event_listener, event: kernel.response, method: onResponse }
My JSON class is here: https://github.com/sourcefabric/Newscoop/blob/master/newscoop/library/Newscoop/Gimme/Json.php
Instead APPLICATION_ENV you can pass to listener parameter kernel.debug.
You can also modify response with (PHP >= 5.4.0, HttpFoundation >= 2.5)
$response->setEncodingOptions($response->getEncodingOptions() | JSON_PRETTY_PRINT);

Grails 2.5 REST PUT not getting called

Grails 2.4 RESTful controller.
I have a basic question. I have a RESTful controller with simple domain class and my GET, POST works fine.
How do I send PUT JSON request?
I am using default RESTful generated controllers
url -i -X POST -H "Content-Type: application/json" -d '{"roleId":1,"username":"testuser5"}' http://localhost:8090/testapp/User
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 03 Jul 2014 02:07:13 GMT
{"id":null,"userId":79,"username":"testuser5"}
Then I tried PUT using same above JSON response (removed id:null and changed the username):
curl -i -X PUT -H "Content-Type: application/json" -d '{"userId":79,"username":"testuser6"}' http://localhost:8090/testapp/User
Request goes to index and I get list of users. What I am doing wrong? How do I invoke "update' method? If I add my own method and I do PUT, my own method gets invoked.
Domain class:
class User {
Integer userId
String username
static mapping = {
table 'user'
version false
id name:'userId', column: 'user_id'
}
static constraints = {
username blank:false, nullable:false
}
}
RESTful controller:
class UserController extends RestfulController {
static responseFormats = ['json', 'xml']
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond User.list(params), model:[userInstanceCount: User.count()]
}
def show(User userInstance) {
respond userInstance
}
def create() {
respond new User(params)
}
#Transactional
def update(User userInstance) {
println "*** in update "
if (userInstance == null) {
notFound()
return
}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'edit'
return
}
userInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'User.label', default: 'User'), userInstance.id])
redirect userInstance
}
'*'{ respond userInstance, [status: OK] }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
You're missing the call to user.validate() prior to calling hasErrors(). See
https://github.com/grails/grails-core/blob/master/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy#L99