I am currently using Micronaut with the following request bean and controller:
...
#Introspected
public final class Bean {
private final HttpRequest<?> httpRequest;
#Nullable
#Positive
private final Integer value;
...
}
...
#Controller("/api/example")
public class ExampleController {
#Get
#Produces(MediaType.APPLICATION_JSON)
public HttpResponse<?> read(#Valid #RequestBean Bean bean) {
Map<String, Object> content = Map.of(
"bean", bean.toString()
);
return HttpResponse.ok(content);
} //read
}
The issue I am having is that value does not seem to be validated when a non-integral value is provided, such as "test". Instead, value is set to null in the bean.
I was hoping to make value optional, hence the #Nullable annotation. Is there any easy way to detect that a non-integral value was passed in for value and send back an error? If I provide a negative number, a nice error message is sent back for me:
{
"message": "Bad Request",
"_links": {
"self": {
"href": "/api/example?value=-1",
"templated": false
}
},
"_embedded": {
"errors": [
{
"message": "bean.value: must be greater than 0"
}
]
}
}
Thanks!
Related
Asp net core web API, I am trying to return a custom response for the model validator. But ValidateModelFilter is not called when the required field, not in the request.
ValidateModelFilter.cs
public class ValidateModelFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var response = new Model
{
error = context.ModelState.ToString()
};
context.Result = new BadRequestObjectResult(response);
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.Filters.Add(typeof(ValidateModelFilter)));
}
I am getting a response like this
{
"errors": {
"Firstname": [
"The Firstname field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|e6752549-4142e91f1074e978."
}
I want to return a response like
{
"error": "The Firstname field is required."
}
The link shows how we have to disable the default Model Binding Exception filter that is returning a 400 error and short circuits the pipeline. Only then the OnActionExecuting method in our custom ActionFilterAttribute is actually getting executed. Everything then works as expected.
https://stackoverflow.com/a/51522487/14924779
I want to use IOptions to get configuration via POCO but it throws the error message 'Model bound complex types must not be abstract or value types and must have a parameterless constructor'
DatabaseSettings.cs
public class DatabaseSettings
{
public string MongoDBServer { get; set; }
}
appsettings.json
"DatabaseSettings": {
"MongoDBServer": "localhost"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.Configure<DatabaseSettings>(Configuration.GetSection("DatabaseSettings"));
}
Controller
public IActionResult Create(IOptions<DatabaseSettings> options)
{
string test = options.Value.MongoDBServer;
return View();
}
I don't know how to handle it. Do you have an advise for me? Thanks!
I had the same issue. I found this answer helpful.
Please try to add [FromServices] to the controller action:
public IActionResult Create([FromServices] IOptions<DatabaseSettings> options)
I have this ASP.NET Core 2.0 MVC Controller:
[Route("api/[controller]")]
public class SampleDataController : Controller
{
[HttpGet("[action]")]
public Example Demo()
{
return new Example("test");
}
public class Example
{
public Example(string name)
{
Name = name;
}
public string Name { get; }
public IEnumerable<Example> Demos
{
get { yield return this; }
}
}
}
When querying /api/SampleData/Demo, I get as response body:
{"name":"test","demos":[
...which is obviously very broken JSON-like output.
How and where do I have to configure my ASP.Net Core 2.0 MVC-based app to make the framework serialize circular references in a way that does not break the output? (For example, by introducing $ref and $id.)
In order to switch on references for JSON.Net serialization, you should set PreserveReferencesHandling property of SerializerSettings to PreserveReferencesHandling.Objects enum value.
In ASP.Net Core you could do it by following adjustment in Startup.ConfigureServices method:
services.AddMvc()
.AddJsonOptions(opt =>
{
opt.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
});
Now the model will be serialized to following correct JSON:
{
"$id": "2",
"name": "test",
"demos": [ { "$ref": "2" } ]
}
I have created Spring Boot app, in this app I have
#RestController
public class OfferController {
#RequestMapping(value = "/saveOffer", method = RequestMethod.POST)
public void saveOffer(#RequestBody Offer offer) {
//...
}
}
Offer class contain nested property of Address type
public class Offer {
private String title;
private Address address;
//... getters setters etc
}
When I'm sending JSON from UI
{
"offer": {
"title":"TheBestOffer",
"address": {
"city": "Warsaw"
}
}
}
My REST controller receives Offer, Address property is null but title property contains value "TheBestOffer" (as it was sended).
As I assume JACKSON delivered with Spring boot require some extra configuration for nested objects? I have tried to do this but it didn't work :/
Spring does this automatically, i think your problem is with the json.
You need to remove offer tag.
{
"title":"TheBestOffer",
"address": {
"city": "Warsaw"
}
}
I'm working on building a WebAPI based OData service and I’m having issues with navigation links. Basically I have two classes where one has a reference to another. When I request either atom or verbose JSON I can see that I have a link between the two. However, I’d like to customize the uri to have it point to a different location rather than the default assumed by the OData library.
Using a simple example, assume that I have two entity sets called ‘entity1’ and ‘entity2’. These are exposed as OData services located at: /api/entities1 and /api/entities2 respectively.
Here’s my sample model code:
public class Entity1 {
public int ID { get; set; }
public string Name { get; set; }
public virtual Entity2 OtherEntity { get; set; }
}
public class Entity2 {
public int ID { get; set; }
public string Value { get; set; }
}
I’m using the ODataConventionModelBuilder to register these as follows:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entity1>("entities1");
builder.EntitySet<Entity2>("entities2");
IEdmModel model = builder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "api", model: model);
I've implemented the controller as an EntitySetController. All of this works as expected and I get the following response when I request verbose JSON:
{
"d": {
"results": [{
"__metadata": {
"id": "http://localhost:37826/api/entities1(1)",
"uri": "http://localhost:37826/api/entities1(1)",
"type": "ODataSample.Models.Entity1"
},
"OtherEntity": {
"__deferred": {
"uri": "http://localhost:37826/api/entities1(1)/OtherEntity"
}
},
"ID": 1,
"Name": "First Entity"
}]
}
}
What I’d like to do is to have the ‘OtherEntity’ field in an Entity1 instance refer to the associated Entity2 instance under /api/entities2 so that the link appears something like /api/entities2(2) (assuming the ID of the Entity2 instance is '2').
I know that I could just make the type of ‘OtherEntity’ a Uri and insert the appropriate value in my controller but that seems a bit of a hack (but I could be wrong). From what understand about OData, I believe the right way to do this is to modify the navigation property but I’m not sure how or where.
Any help is appreciated. Thanks in advance.
Cheers,
Steve
You could do something like the following:
var entities1 = builder.EntitySet<Entity1>("Entities1");
entities1.HasNavigationPropertyLink(entities1.EntityType.NavigationProperties.First(np => np.Name == "OtherEntity"),
(context, navigation) =>
{
return new Uri(context.Url.ODataLink(new EntitySetPathSegment("Entities2"), new KeyValuePathSegment(context.EntityInstance.OtherEntity.Id.ToString())));
}, followsConventions: false);