How to include RegexOptions in OpenAPI json to indicate lower case - fluentvalidation

I am writing an application that calls an API using code that is generated using autorest. The API has Fluent Validation and writes the expression to the swagger.json document, but the validator behind it uses Regex.IgnoreCase which is not exposed in the json. Is there a field in OpenApi spec where this could be set? Or would the RegexExpression have to be rewritten to take into account the ignore case option?
.Net Core 2.1 FluentValidation.AspNetCore (8.0.100)
MicroElements.Swashbuckle.FluentValidation (0.8.2)
Auto Rest
Fluent Validation Setup
public class UserIdentifierValidator : AbstractValidator<UserIdentifier>
{
public UserIdentifierValidator()
{
RuleFor(x => x.Email)
.EmailAddress()
.NotEmpty();
}
}
swagger.json
"email": {
"title": "Email",
"description": "The email of the user",
"minLength": 1,
"pattern": "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))#((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-||_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+([a-z]+|\\d|-|\\.{0,1}|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$",
"type": "string"
}
AutoRest
if (Email != null)
{
if (Email.Length < 1)
{
throw new ValidationException(ValidationRules.MinLength, "Email", 1);
}
if (!System.Text.RegularExpressions.Regex.IsMatch(Email, "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))#((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-||_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+([a-z]+|\\d|-|\\.{0,1}|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$"))
{
throw new ValidationException(ValidationRules.Pattern, "Email", "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))#((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-||_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+([a-z]+|\\d|-|\\.{0,1}|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])?([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$");
}
}

Related

NSwag generated client still serializes string for text/plain body

UPDATE: I went ahead and created an issue on NSwag after looking through its code. You can see it here: https://github.com/RicoSuter/NSwag/issues/3824
I have a functioning api endpoint that accepts "text/plain" as the body. The user of this endpoint is a third-party that controls the content type so I can't change that. I'm using NSwag to generate a c# client based on a swagger.json.
My main problem is that the generated client's function for calling this endpoint still serializes the string body, which causes the endpoint to fail to parse. I'm not 100% certain if this is a bug in my swagger.json or if it's something unintentional, because the json is also generated. This is why I'm not posting this on the NSwag github issues currently.
Here's what the swagger.json looks like:
{
"openapi": "3.0.1",
"info": {
"title": "PlainTextParser",
"version": "1.0"
},
"paths": {
"/api/v1/text": {
"post": {
"tags": [
"TextEvent"
],
"summary": "Parses a plain text body",
"operationId": "PostTextEvent",
"requestBody": {
"description": "Accepts a plain text body",
"content": {
"text/plain": {
"schema": {
"type": "string",
"nullable": true
}
}
}
},
"responses": {
"202": {
"description": "Success"
}
}
}
}
},
"components": { }
}
When I run nswag on it, I get this inside of the generated client:
public virtual async System.Threading.Tasks.Task PostTextEventAsync(string body, System.Threading.CancellationToken cancellationToken)
{
//...
var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value));
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain");
//...
}
The SerializeObject method call is what is causing the issue. When I removed it everything worked fine. You can even see on the second line there that it understands the content type, which is why I'm confused why it's trying to serialize it.
So is there something I'm missing in the swagger.json or is there a bug in NSwag?
I do realize I can work around this by making my API endpoint reformat the string to its intended state, but that feels like a hack.

JSON Schema v7: formatMinimum & formatMaximum validate everything

I am using ajv json schema library (v7) and trying to validate a date based on some value. It looks pretty straightforward with using formatMinimum/formatMaximum but it seems that every date is validated when using these keywords
Here's my schema
"some-date": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"value": {
"type": "string",
"format": "date-time",
"formatMinimum": "2021-03-10T14:25:00.000Z"
}
}
}
}
}
Here's the json:
{
"some-date": {
"data": {
"value": "2011-03-10T14:25:00.000Z"
}
}
}
Here's how I am validating:
const ajv = new Ajv({allErrors: true})
require('ajv-formats')(ajv)
require('ajv-errors')(ajv)
require('ajv-keywords')(ajv)
const validate = ajv.validate(mySchema)
const isValid = validate(myJSON)
I've tried it on JSONSchemalint and it validates the above json with the given schema. Also, I have tried with several dates and it validates everything.
Please let me know if I am missing something.
Thanks
I'm not sure where you're getting formatMinimum and formatMaximum from, but they are not standard keywords in the JSON Schema specification, under any version. Are they documented as supported keywords in the implementation that you are using?

Return string from Web API .NET Core get operation

I have a get operation that I want to return a string from. An example would be
"000875"
When I return this string from a controller in my Web API Controller in full .NET, it formats it like this:
{
"Property": "000875"
}
When I return the string in my converted .NET Core Controller it returns this:
{
"$id": "1",
"$type": "System.Net.Http.HttpResponseMessage, System.Net.Http",
"Version": "1.1",
"Content": {
"$id": "2",
"$type": "System.Net.Http.StringContent, System.Net.Http",
"Headers": [
{
"Key": "Content-Type",
"Value": [
"application/json; charset=utf-8"
]
}
]
},
"StatusCode": "OK",
"ReasonPhrase": "OK",
"Headers": [],
"TrailingHeaders": [],
"RequestMessage": null,
"IsSuccessStatusCode": true
}
It is interesting to note that the value is not even in there!
I am running some interesting JSON Serialization to make BreezeJs work with .NET Core. It is possible that it is the cause of this weirdness:
.AddNewtonsoftJson(opt =>
{
// Let Breeze say how we serialize. This adds in the Type and Id options the way breeze expects
var jsonSerializerSettings = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings);
......
I am hoping for a way to get strings through without all this mess. Can that be done?
I get the impression that the subject action definition returns HttpResponseMessage.
public HttpResponseMessage MyAction(....
HttpRequestMessage is no longer a first class citizen in asp.net-core framework and will be treated as a normal model and serialized.
That explains the JSON you are seeing with your controller
The syntax needs to be updated to return IActionResult derived responses
public IActionResult MyAction() {
//...
return Ok("000875");
}
ActionResult<T>
public ActionResult<string> MyAction() {
//...
if(somecondition)
return NotFound();
return "000875";
}
or the model itself.
public string MyAction() {
//...
return "000875";
}
Reference Controller action return types in ASP.NET Core Web API

IdentityServer4 read client claims from appsettings.json

how can I read client claims from the appsettings.json file?
I have this appsettings.json:
"IdentityServer": {
"Clients": [
{
"Enabled": true,
"ClientId": "client1",
"AlwaysSendClientClaims": true,
"Claims": [
{
"Type": "custom_claim1",
"Value": "value1"
},
{
"Type": "custom_claim2",
"Value": "value2"
}
]
}
]
}
And, I load the clients config like the docs says:
var builder = services.AddIdentityServer(opts =>
{
/// Opts removed for simplicity
})
.AddInMemoryClients(Configuration.GetSection("IdentityServer:Clients"));
All is working fine, except for the client claims. I can not see them in Jwt.io decode tool.
There is a problem binding the Claims collection in the Clients[] from appSettings.json due to the fact that the current implementation of the Claim object can not be deserialized from json.
https://github.com/IdentityServer/IdentityServer4/issues/2573
and here
https://github.com/IdentityServer/IdentityServer4/pull/3887/files/ed14abc204960b2d5ca3418a868882a698e54d90

Differences between api and model swagger

I'm new with swagger and I'm defining an API.
Can I define an api with swagger without needing to use the #ApiModelProperty annotation? What exactly is an object model in swagger?
Yes , you can define an API without using the #ApiModelProperty. Models object is not a required field in the OpenAPI Spec.
The Models Object holds a field per model definition, and this is different than the structure of the other objects in the spec. It follows a subset of the JSON-Schema specification.
#ApiModelProperty defines the properties of that object. Also Model Object is a part of the response in Swagger
Example you have a model - User class.
class User {
int id;
String name;
int age;
}
Model Object will contain information about User.
{
"User": {
"id": "User",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
}
}
}
#ApiModelProperty is used in the Java class User to produce this JSON by defining id, name and age inside it.