How do I control the output of NJsonSchema for decimals - njsonschema

I have a C# object like so:
public class Foo {
public decimal Number {get;set;}
}
And I create a json schema like so:
var schema = await JsonSchema4.FromTypeAsync(typeof(Foo));
var jsonSchema = schema.ToJson();
return jsonSchema;
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Foo",
"type": "object",
"additionalProperties": false,
"properties": {
"SomeNumber": {
"type": "number",
"format": "decimal"
}
}
}
How do I prevent the property "format": "decimal" from outputting in the resulting schema?
edit to add: Without modifying the class Foo -- I don't have access to it.

Related

Using AJV in Postman seems to ignore nesting/children

I'm trying to validate JSON response messages according to schema.
But as soon as an attribute has the type "array" or "object", AJV seems to ignore them and does not see the nested attribute within that object or array.
I started trying to break up the schema into multiple smaller ones so all objects/arrays are covered, but this is a tedious task and I'm hoping I'm just using AJV incorrectly.
Example schema (simplified):
{
"type": "object",
"required": [
"MainThing"
],
"properties": {
"MainThing": {
"type": "string",
"description": "Some kind of string.",
"example": "This is some kind of string."
},
"NestedThing": {
"type": "object",
"required": [
"NestedAttribute"
],
"properties": {
"NestedAttribute": {
"type": "String",
"description": "A nested string.",
"example": "This is a nested string"
}
}
}
}
}
If I change the NestedAttribute to an Integer instead of a String, the schema validation in Postman will tell me the response is valid against the schema. While it's not, because the response will contain a NestedAttribute which is a String value.
The following response would be deemed valid, while it's not:
{
"MainThing": "The main thing",
"NestedThing": {
"NestedAttribute": 12345
}
}
My Postman testcode:
var Ajv = require('ajv'),
ajv = new Ajv({logger: console}),
schema = JSON.parse(pm.variables.get("THIS_IS_MY_AWESOME_SCHEMA"));
pm.test('My schema is valid', function() {
var data = pm.response.json();
pm.expect(ajv.validate(schema, data)).to.be.true;
});
If anyone can point me in the right direction, that would be greatly appreciated!

How to Marshal/Unmarshal a common JSON & BSON key/field that can have two different formats in Go?

I currently have mongo data stored in two forms (specifically for content key) in a collection. Partial sample data shown below:
Format 1.
{
"type": "text",
"content": "foobar",
"extraTextData": "hello text"
}
Format 2
{
"type": "group",
"content": [
{
"type": "text",
"content": "grouped-foobar"
},
{
"type": "image",
"url": "https://abc.jpg"
},
],
"extraGroupData": "hello group"
}
My attempt to structure this in golang is below.
type C struct {
Type string `json:"type" bson:"type"`
Content ???
*TextC
*GroupC
}
type TextC struct {
ExtraTextData `json:"extraTextData" bson:"extraTextData"`
}
type GroupC struct {
ExtraGroupData `json:"extraGroupData" bson:"extraGroupData"`
}
I am having issues on how to setup the structure for "content" field that works for both the formats, TextC and GroupC.
Content for GroupC can be array of C like - Content []C
Content for TextC can also be string type.
Can someone please help & give an example on how to tackle this situation?
Format2 json is Invalid. You can check it here : https://jsonlint.com/
I have created a sample scenario for your case.
You can try it here: https://go.dev/play/p/jaUE3rjI-Ik
Use interface{} like this:
type AutoGenerated struct {
Type string `json:"type"`
Content interface{} `json:"content"`
ExtraTextData string `json:"extraTextData,omitempty"`
ExtraGroupData string `json:"extraGroupData,omitempty"`
}
And you should also remove comma from Format2:
{
"type": "group",
"content": [
{
"type": "text",
"content": "grouped-foobar"
},
{
"type": "image",
"url": "https://abc.jpg"
}
],
"extraGroupData": "hello group"
}
If you don't remove comma then it will through an error like this:
invalid character ']' looking for beginning of value

Spring boot swagger multipart with json content and attachment

I've a requirement to upload any file content using Swagger-3 along with some metadata information as a JSON within a single request. Therefore I configured following into my swagger:
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"metadata": {
"$ref": "#/components/schemas/Attachment"
},
"file": {
"type": "string",
"format":"binary",
"description": "Actual File Attachment"
}
}
}
}
},
"description": "The Attachment record / entry be created",
"required": true
}
It translates to following when I build the controller object:
#ApiOperation(value = "Upload attachments to a existing Ticket", nickname = "uploadAttachment", notes = "", response = Attachment.class, responseContainer = "List", tags={ "changeRequest", })
#RequestMapping(value = "/changeRequest/attachment/{id}",
produces = { "application/json" },
consumes = { "multipart/form-data" },
method = RequestMethod.POST)
public ResponseEntity<List<Attachment>> uploadAttachment(#ApiParam(value = "Identifier of the Change Request",required=true) #PathVariable("id") String id,#ApiParam(value = "Application ID invoking the call" ,required=true) #RequestHeader(value="X-App-Id", required=true) String xAppId,#NotNull #ApiParam(value = "To track unique transaction across multiple systems for audit trail", required = true) #Valid #RequestParam(value = "X-Transaction-Id", required = true) String xTransactionId,#ApiParam(value = "Authorization header" ) #RequestHeader(value="authorization", required=false) String authorization,#ApiParam(value = "", defaultValue="null") #RequestParam(value="metadata", required=false) Attachment metadata, #ApiParam(value = "file detail") #Valid #RequestPart("file") MultipartFile file) {
ResponseEntity<List<Attachment>> responseEntity = new ResponseEntity<>(HttpStatus.OK);
responseEntity.getBody().add(metadata);
return responseEntity;
}
Following is the Attachment schema definition:
"Attachment": {
"type": "object",
"description": "Attachment Metadata definition",
"properties": {
"description": {
"type": "string",
"description": "A narrative text describing the content of the attachment"
},
"href": {
"type": "string",
"description": "Reference of the attachment"
},
"id": {
"type": "string",
"description": "Unique identifier of the attachment"
},
"mimeType": {
"type": "string",
"description": "The mime type of the document as defined in RFC 2045 and RFC 2046 specifications."
},
"name": {
"type": "string",
"description": "The name of the file"
},
"path": {
"type": "string",
"description": "The path of the attached file"
},
"size": {
"type": "integer",
"description": "The size of the file (sizeUnit if present indicates the unit, otherwise kilobytes is the default)."
},
"sizeUnit": {
"type": "integer",
"description": "The unit size for expressing the size of the file (MB,kB...)"
},
"url": {
"type": "string",
"description": "Uniform Resource Locator, is a web page address (a subset of URI)"
},
"validFor": {
"$ref": "#/components/schemas/TimePeriod",
"description": "Period of validity of the attachment"
},
"#type": {
"type": "string",
"description": "The class type of the actual resource (for type extension)."
},
"#schemaLocation": {
"type": "string",
"description": "A link to the schema describing a resource (for type extension)."
},
"#baseType": {
"type": "string",
"description": "The base type for use in polymorphic collections"
}
}
}
In the example above, Attachment metadata is what I am trying to pass as part of the SOAP API test. However I keep getting following error:
Mon Oct 12 17:06:28 IST 2020:DEBUG:<< "{"timestamp":"2020-10-12T11:36:28.371Z","status":500,"error":"Internal Server Error","message":"Failed to convert value of type 'java.lang.String' to required type 'com.bell.na.nt.change.swagger.model.Attachment'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.bell.na.nt.change.swagger.model.Attachment': no matching editors or conversion strategy found","path":"/changeManagement/api/v1/changeRequest/attachment/1234"}"
Why is the string not being converted and mapped to the JSON object. Not sure I am missing anything. Following is what my json looks like.
{"#baseType": "string", "#schemaLocation": "string", "#type": "string", "description": "string", "href": "string", "id": "string", "mimeType": "string", "name": "string", "path": "string", "size": 0, "sizeUnit": 0, "url": "string", "validFor": { "endDateTime": "2020-10-11T19:06:40.586Z", "startDateTime": "2020-10-11T19:06:40.586Z"}}
Postman Request
Turns out I had to add the a converter for converting the string representation of the JSON to desired Swagger generated Model object something like:
#Component
public class StringToAttachmentObjectConverter implements Converter<String, Attachment> {
Logger logger = LoggerFactory.getLogger(StringToAttachmentObjectConverter.class);
#Autowired
private ObjectMapper objectMapper;
DocumentContext docContext = null;
#Override
public Attachment convert(String source) {
try {
String sourceString = JsonPath.using(NetsUtilityJSONDatumUtils.jsonPathConfig).parse(source).jsonString();
return objectMapper.readValue(sourceString, Attachment.class);
} catch (JsonParseException e) {
logger.error("Error While converting the String: \n" + source, e);
} catch (JsonMappingException e) {
logger.error("Error While converting the String: \n" + source, e);
} catch (IOException e) {
logger.error("Error While converting the String: \n" + source, e);
}
return null;
}
}
Not sure if there is any better way or if I am defying any best practice(s) but this did the trick for me.

Having mapper_parsing_exception when creating elasticsearch index all in Fields

I'm creating a winston-elasticsearch logger usin Kibana, where I need to save all what is happen in the app (request, apis, ...).I used this( https://github.com/vanthome/winston-elasticsearch) I defined a json mapping template. Also a transformer.js file where I define a Transformer function to transform log data as provided by winston into a message structure which is more appropriate for indexing in ES.
then I use the winston-elasticsearch to create new Es instance:
exports.mappingTemplate = require('../../../index-template-mapping.json');
const TransportersElastic = new Elasticsearch({
index: 'soapserver',
level: 'info',
indexPrefix: 'logs',
transformer: transformer,
ensureMappingTemplate: true,
mappingTemplate: mappingTemplate,
flushInterval: 2000,
waitForActiveShards: 1,
handleExceptions: false,...
But I keep getting Elasticsearch index error of type: 'mapper_parsing_exception' reasons like : failed to parse field [fields.result.status] of type [text]'
illegal_argument_exception' reason : 'failed to parse field [fields.rows.tmcode] of type [long]'
Here transformer.js:
exports.mappingTemplate = require('../../../index-template-mapping.json');
exports.transformer = (logData) => {
const transformed = {};
transformed['#timestamp'] = new Date().toISOString();
transformed.source_host = os.hostname();
transformed.message = logData.message;
if (typeof transformed.message === 'object') {
transformed.message = JSON.stringify(transformed.message);
I need help, suggestion how to resolve those error and succeed the Mapping.
Here the index-mapping-template.json
{
"mapping": {
"_doc": {
"properties": {
"#timestamp": {
"type": "date"
},
"fields": {
"ignore_malformed": true,
"dynamic": "true",
"properties": {}
},
"message": {
"type": "text"
},
"severity": {
"type": "keyword"
}
}
}
}
}

Get the mapping of an Object type field in Spring Data Elasticsearch

I'm working in a project with Elasticsearch and Spring Data Elasticsearch.
I need to get the mapping of an object type of my index. My #document class looks like:
#Document(indexName = "esbsdocuments", type = ESBSDocumentEls.MAPPING_TYPE)
public class ESBSDocumentEls extends ESBSDomainModel {
...
#Field(type =FieldType.Object, store = false)
private Object metadata;
...
}
If I try to get it via http://xxx:9200/_mapping I can get the mapping for "metadata" field correctly:
...
"metadata": {
"properties": {
"APP": {
"type": "string"
},
"APPDST": {
"type": "string"
},
"APPSUB": {
"type": "string"
},
"COUNTSUB": {
"type": "string"
},
"DOMINIO": {
"type": "string"
},
"DUPLICATE": {
"type": "string"
},
"EXCLUDEFIELDNAMES": {
"type": "string"
},
"FECHA": {
"type": "string"
},
"ID": {
"type": "string"
},
"IDF": {
"type": "string"
},
"IDSUB": {
"type": "string"
},
"LOCALEDATE": {
"type": "string"
},
"MENSAJE": {
"type": "string"
},
"TAMANYO": {
"type": "string"
},
"TIPO": {
"type": "string"
},
"VERSION": {
"type": "string"
}
}
},
...
But when I try it in code with
Map mapping = elasticsearchTemplate.getMapping(ESBSDocumentEls.class);
I can only get:
... (definition of metadata dynamic templates)
metadata={type=object}
...
How can I get the detailed mapping definition using ElasticSearchTemplate or another Spring Data Elasticsearch class??
Thank you very much!
Finally I got a solution.
Instead of using elasticSearchTemplate, I have used the els java api:
GetMappingsResponse res = elasticSearchClient.admin().indices().getMappings(new GetMappingsRequest().indices(indexName)).get();
ImmutableOpenMap<String, MappingMetaData> indexMappings = res.mappings().get(indexName);
MappingMetaData mappingMetaData = indexMappings.get(mappingType);
Map<String, Object> map = mappingMetaData.getSourceAsMap();
Map<String, Object> metadataProperties = (Map<String, Object>) ((Map<String, Object>) map.get("properties")).get("metadata");
Map<String, Object> metadataList = (Map<String, Object>) metadataProperties.get("properties");
This way I can get a Map with all my "metadata" fields. You can't get the api client from the elasticSearchTemplate (https://jira.spring.io/browse/DATAES-124) so you have to inject it :(
I hope this help someone!
You can now use the public <T> Map getMapping(Class<T> clazz) method which is already available in the template. It returns a map of fields and types.
elasticSearchTemplate.getMapping(ESBSDocumentEls.class);

Resources