Swagger 2 Use fields instead of getters+setters - swagger

I have the following java REST service
#GET
#Path("/{customerId}")
#Operation(
summary = "Test summary",
description = "Test desciption",
responses = {
#ApiResponse(
responseCode = "200",
content = #Content(
schema = #Schema(implementation = CustomerDto.class),
mediaType = "application/json"),
description = "CustomerDto description"),
#ApiResponse(
responseCode = "400",
description = "Description for 400 status")
//Here you can add all response statuses and their's descriptions
})
public CustomerDto findCustomerById(#Parameter(description = "Id of the customer", required = true) #PathParam("customerId") Long customerId) {
return apiFacade.getCustomerDtoByCustomerId(customerId);
}
Simple dto-class
public class CustomerDto {
private TestInfo testInfo;
}
Simple subclass
public class TestInfo {
private Long testId;
private Long checkId;
public TestInfo(Long testId, Long checkId) {
this.testId = testId;
this.checkId = checkId;
}
public Long getTestId() {
return testId;
}
public Long getCheckId() {
return checkId;
}
public boolean isDecisionMade() {
return testId != null || checkId != null;
}
}
I'd like to see TestInfo-json without 'decisionMade' section. Can you help me It is possible?
"TestInfo" : {
"type" : "object",
"properties" : {
"testId" : {
"type" : "integer",
"format" : "int64"
},
"checkId" : {
"type" : "integer",
"format" : "int64"
},
"decisionMade" : {
"type" : "boolean"
}
}
}
Is it possible to tell swagger use class-fields instead of getter+setter?
I use swagger version 2.2.2. Generate json via BaseOpenApiResource. All configs are default.

I have found the decision:
Json.mapper().setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
Json.mapper().setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

Related

Do I use Strategy pattern correctly in my dart code?

I'm trying to apply a strategy pattern in my dart code, but I don't know why the overridden method in child class doesn't get called.
Below is an example push notification message that will be sent to mobile devices, the data in "content" node can be different depends on the "type" value. In order to deserialize the message correctly, I created classes as below,
{
"priority": "high",
"to": "123342"
"notification": {
"body": "this is a body",
"title": "this is a title"
},
"data": {
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"status": "done",
"type": "Order",
"content" : {
"order_id" : "[order_id]"
}
},
}
class Message<T extends BaseDataContent> {
String to;
String priority;
Notification notification;
Data<T> data;
Message({this.to, this.priority, this.notification, this.data});
Message.fromJson(Map<String, dynamic> json) {
to = json['to'];
priority = json['priority'];
notification = json['notification'] != null
? new Notification.fromJson(json['notification'])
: null;
data = json['data'] != null
? new Data.fromJson(json['data'])
: null;
}
}
class Notification {
String title;
String body;
Notification({this.title, this.body});
Notification.fromJson(Map<String, dynamic> json) {
title = json['title'];
body = json['body'];
}
}
class Data<T extends BaseDataContent> {
String click_action;
String status;
String type;
T content;
Data({this.click_action, this.status, this.type, this.content});
Data.fromJson(Map<String, dynamic> json) {
click_action = json['click_action'];
status = json['status'];
type = json['type'];
content = json['content'] != null?
this.content.deserializeContent(json['content'])
: null;
}
}
abstract class BaseDataContent{
BaseDataContent deserializeContent(Map<String, dynamic> jsonString);
}
class OrderMessageContent extends BaseDataContent {
int orderId;
OrderMessageContent({this.orderId}) : super();
#override
OrderMessageContent deserializeContent(Map<String, dynamic> jsonString){
///Deserialize Content json.
}
}
To test my code, I wrote some demo code as below
String json = '{"priority": "high", "to": "343434", "data":{"click_action":"343434","content":{"order_id" : "1234"}}}';
var jsonResponse = jsonDecode(json);
var result = Message<OrderMessageContent>.fromJson(jsonResponse);
The code is failed when it reaches to line
this.content.deserializeContent(json['content'])
The error message is "NoSuchMethodError: the method deserializeContent was called on null. Receiver:null". I don't know why deserializeContent method in OrderMessageContent doesn't get called, please help.
Thanks.
In Data constructor you called a method on a null object, where you called deserializeContent. You should either make that method static or initialize content first.
Data.fromJson(Map<String, dynamic> json) {
click_action = json['click_action'];
status = json['status'];
type = json['type'];
content = json['content'] != null?
this.content.deserializeContent(json['content'])
: null;
}

DocumentDB LINQ Query - Select method not supported

The Application:
.Net Standard Class Library (Containing a series of Repositories)
Latest version https://www.nuget.org/packages/Microsoft.Azure.DocumentDB.Core
Azure Cosmos DB Emulator
Sample Document Structure:
{
"ProfileName": "User Profile 123",
"Country": "UK",
"Tags": [{
"Id": "686e4c9c-f1ab-40ce-8472-cc5d63597263",
"Name": "Tag 1"
},
{
"Id": "caa2c2a0-cc5b-42e3-9943-dcda776bdc20",
"Name": "Tag 2"
}],
"Topics": [{
"Id": "baa2c2a0-cc5b-42e3-9943-dcda776bdc20",
"Name": "Topic A"
},
{
"Id": "aaa2c2a0-cc5b-42e3-9943-dcda776bdc30",
"Name": "Topic B"
},
{
"Id": "eaa2c2a0-cc5b-42e3-9943-dcda776bdc40",
"Name": "Topic C"
}]
}
The Problem:
The issue I have is that any LINQ query I execute that contains a .Select, returns an error stating that the Select method is not supported.
What I Need?
I want to be able to use a LINQ Expression to return all documents WHERE:
Country = UK
Tags contains a specific GUID
Topics contain a specific GUID
What I Need? I want to be able to use a LINQ Expression to return all documents
In your case, the Tags and Topic are object array, if you use the following linq code it will get null.
var q = from d in client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("database", "coll"))
where d.Country == "UK" && d.Tags.Contains(new Tag
{
Id = "686e4c9c-f1ab-40ce-8472-cc5d63597264"
}) && d.Topics.Contains(new Topic
{
Id = "baa2c2a0-cc5b-42e3-9943-dcda776bdc22"
})
select d;
I also try to override IEqualityComparer for Tag and Topic
public class CompareTag: IEqualityComparer<Tag>
{
public bool Equals(Tag x, Tag y)
{
return x != null && x.Id.Equals(y?.Id);
}
public int GetHashCode(Tag obj)
{
throw new NotImplementedException();
}
}
And try it again then get Contains is not supported by Azure documentDb SDK
var q = from d in client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("database", "coll"))
where d.Country == "UK" && d.Tags.Contains(new Tag
{
Id = "686e4c9c-f1ab-40ce-8472-cc5d63597264"
},new CompareTag()) && d.Topics.Contains(new Topic
{
Id = "baa2c2a0-cc5b-42e3-9943-dcda776bdc22"
}, new CompareTopic())
select d;
My workaround is that we could use the SQL query directly. It works correctly on my side. We also could test it on the Azure portal.
SELECT * FROM root WHERE (ARRAY_CONTAINS(root.Tags, {"Id": "686e4c9c-f1ab-40ce-8472-cc5d63597263"}, true) And ARRAY_CONTAINS(root.Topics, {"Id": "baa2c2a0-cc5b-42e3-9943-dcda776bdc20"}, true) And root.Country = 'UK' )
Query with SDK
FeedOptions queryOptions = new FeedOptions { MaxItemCount = -1 };
var endpointUrl = "https://cosmosaccountName.documents.azure.com:443/";
var primaryKey = "VNMIT4ydeC.....";
var client = new DocumentClient(new Uri(endpointUrl), primaryKey);
var sql = "SELECT * FROM root WHERE (ARRAY_CONTAINS(root.Tags, {\"Id\":\"686e4c9c-f1ab-40ce-8472-cc5d63597263\"},true) AND ARRAY_CONTAINS(root.Topics, {\"Id\":\"baa2c2a0-cc5b-42e3-9943-dcda776bdc20\"},true) AND root.Country = \"UK\")";
var profileQuery = client.CreateDocumentQuery<Profile>(
UriFactory.CreateDocumentCollectionUri("dbname", "collectionName"),sql, queryOptions).AsDocumentQuery();
var profileList = new List<Profile>();
while (profileQuery.HasMoreResults)
{
profileList.AddRange(profileQuery.ExecuteNextAsync<Profile>().Result);
}
Profile.cs file
public class Profile
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
public string Country { get; set; }
public string ProfileName { get; set; }
public Tag[] Tags{ get; set; }
public Topic[] Topics { get; set; }
}
Topic.cs
public class Topic
{
public string Id { get; set; }
public string Name { get; set; }
}
Tag.cs
public class Tag
{
public string Id { get; set; }
public string Name { get; set; }
}

How to add header parameter to specific controller/methods for API.NET web API

I know that I can add header parameter for all API in swagger as described in Web Api How to add a Header parameter for all API in Swagger
With this approach, the header parameter will show up in swagger UI for all APIs.
But not all of my APIs/controllers need the header parameter, is there a way to add header only for specific controller or even a specific API?
Though this post is old, I thought it would help new comers if they get stuck
in the same situation.
public class AddRequiredHeaderParameter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry,
ApiDescription apiDescription)
{
if (operation.parameters == null)
{
operation.parameters = new List<Parameter>();
}
/*System.Diagnostics.Trace.WriteLine(apiDescription.RelativePath +
"=paath");*/
if (apiDescription.RelativePath.Contains(***{url***}))
{
operation.parameters.Add(new Parameter
{
name = "X-User-Token",
#in = "header",
type = "string",
required = false,
description=""
});
operation.parameters.Add(new Parameter
{
name = "authorization",
#in = "header",
description = "Token",
type = "string",
required = true
});
}
else
{
operation.parameters.Add(new Parameter
{
name = "X-User-Token",
#in = "header",
type = "string",
required = false,
description="description"
});
}
}
}
In Asp.Net Core/.net6
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.OpenApi.Models;
namespace YourProduct
{
public class HttpHeaderOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Parameters.Add(new OpenApiParameter
{
Name = "X-your-Custom-header",
In = ParameterLocation.Header,
AllowEmptyValue = true,
Required = false,
Description = "Your custom header Name"
});
}
}
}
in the action
[HttpPost("[action]")]
[SwaggerOperationFilter(typeof(HttpHeaderOperationFilter))] //<-- point of interest
public IActionResult DoSomething([FromBody] YourModel model)
{
. . . . . . .
And don't forget startup.cs
services.AddSwaggerGen(opt =>
{
opt.EnableAnnotations(); // <-- this
}

MultiField mapping using spring-data-elasticsearch annotations

I am trying to use spring-data-elasticsearch to set up mappings for a type that is equivalent to the json configuration below and I am running into issues.
{
"_id" : {
"type" : "string",
"path" : "id"
},
"properties":{
"addressName":{
"type":"multi_field",
"fields":{
"addressName":{
"type":"string"
},
"edge":{
"analyzer":"edge_search_analyzer",
"type":"string"
}
}
},
"companyName":{
"type":"multi_field",
"fields":{
"companyName":{
"type":"string"
},
"edge":{
"analyzer":"edge_search_analyzer",
"type":"string"
}
}
}
}
}
Here is the entity class as it stands now:
#Document(indexName = "test", type="address")
#Setting(settingPath="/config/elasticsearch/test.json") // Used to configure custom analyzer/filter
public class Address {
#Id
private Integer id;
#MultiField(
mainField = #Field(type = FieldType.String),
otherFields = {
#NestedField(dotSuffix = "edge", type = FieldType.String, indexAnalyzer = "edge_search_analyzer")
}
)
private String addressName;
#MultiField(
mainField = #Field(type = FieldType.String),
otherFields = {
#NestedField(dotSuffix = "edge", type = FieldType.String, indexAnalyzer = "edge_search_analyzer")
}
)
private String companyName;
public Address() {}
public Address(AddressDTO dto) {
id = dto.getId();
addressName = dto.getAddressName();
companyName = dto.getCompanyName();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
Preconditions.checkNotNull(id);
this.id = id;
}
public String getAddressName() {
return addressName;
}
public void setAddressName(String addressName) {
this.addressName = addressName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
}
What I am finding is that this results in a mapping like:
"address" : {
"properties" : {
"addressName" : {
"type" : "string",
"fields" : {
"addressName.edge" : {
"type" : "string",
"index_analyzer" : "edge_search_analyzer"
}
}
},
"companyName" : {
"type" : "string",
"fields" : {
"companyName.edge" : {
"type" : "string",
"index_analyzer" : "edge_search_analyzer"
}
}
}
}
}
Which results in two issues:
Id mapping is not done so Elasticsearch generates the ids
Searches on the properties with the custom analyzer do not work properly
If I add the following to override the use of the annotations everything works fine:
#Mapping(mappingPath="/config/elasticsearch/address.json")
Where "address.json" contains the mapping configuration from the top of this post.
So, can anyone point out where I might be going wrong with what I'm trying to achieve?
Is is possible using available annotations or am I going to have to stick with json configuration?
Also, is there a "correct" way to setup index-level configuration via spring-data-elasticsearch, or is that not a supported approach? Currently, I am using the #Setting annotation for this purpose

mvc - jQuery ajax datatable actionlink

I have a datatable in which the data (from the database) is being filled with ajax, I also want a new tablerow with "Details" to show more details of the selected item, but the table only allows data from the database. Here is the view
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$('#myDataTable').dataTable({
"bProcessing": false,
"bServerSide": true,
"sAjaxSource": 'AjaxDataProvider',
"aoColumns": [
{
"sName": "ID",
},
{ "sName": "Student_naam" },
{ "sName": "klas" },
{ "sName": "adres" },
{ "sName": "woonplaats" },
{ "sName": "details" }
]
})
});
</script>
and I have a table beneath with some code including this:
<td>
#Html.ActionLink("Details", "Index", "StudentGegevens", new {id = item.studentnr})
</td>
Here is my controller
public ActionResult AjaxDataProvider(JQueryDataTableParamModel param)
{
var allStudents = hoi.STUDENT.ToList();
IEnumerable<STUDENT> filteredStudents;
if (!string.IsNullOrEmpty(param.sSearch))
{
//Used if particulare columns are filtered
var roepnaamFilter = Convert.ToString(Request["sSearch_1"]);
var adresFilter = Convert.ToString(Request["sSearch_2"]);
var woonplaatsFilter = Convert.ToString(Request["sSearch_3"]);
var klasFilter = Convert.ToString(Request["sSearch_4"]);
//Optionally check whether the columns are searchable at all
var isNameSearchable = Convert.ToBoolean(Request["bSearchable_1"]);
var isAddressSearchable = Convert.ToBoolean(Request["bSearchable_2"]);
var isTownSearchable = Convert.ToBoolean(Request["bSearchable_3"]);
var isClassSearchable = Convert.ToBoolean(Request["bSearchable_4"]);
filteredStudents = hoi.STUDENT.ToList()
.Where(c => isNameSearchable && c.roepnaam.ToLower().Contains(param.sSearch.ToLower())
||
isAddressSearchable && c.adres.ToLower().Contains(param.sSearch.ToLower())
||
isTownSearchable && c.woonplaats.ToLower().Contains(param.sSearch.ToLower())
||
isClassSearchable && c.klas.ToLower().Contains(param.sSearch.ToLower()));
}
else
{
filteredStudents = allStudents;
}
var isNameSortable = Convert.ToBoolean(Request["bSortable_1"]);
var isAddressSortable = Convert.ToBoolean(Request["bSortable_2"]);
var isTownSortable = Convert.ToBoolean(Request["bSortable_3"]);
var isClassSortable = Convert.ToBoolean(Request["bSortable_4"]);
var sortColumnIndex = Convert.ToInt32(Request["iSortCol_0"]);
Func<STUDENT, string> orderingFunction = (c => sortColumnIndex == 1 && isNameSortable ? c.roepnaam :
sortColumnIndex == 2 && isClassSortable ? c.klas :
sortColumnIndex == 3 && isAddressSortable ? c.adres :
sortColumnIndex == 4 && isTownSortable ? c.woonplaats :
"");
var sortDirection = Request["sSortDir_0"]; // asc or desc
if (sortDirection == "asc")
{
filteredStudents = filteredStudents.OrderBy(orderingFunction);
}
else
{
filteredStudents = filteredStudents.OrderByDescending(orderingFunction);
}
var displayedStudents = filteredStudents.Skip(param.iDisplayStart).Take(param.iDisplayLength);
var result = from c in displayedStudents select new[] { Convert.ToString(c.studentnr), c.roepnaam, c.klas, c.adres, c.woonplaats, "Here is the thing I dont know what to fill in" };
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allStudents.Count(),
iTotalDisplayRecords = filteredStudents.Count(),
aaData = result
},
JsonRequestBehavior.AllowGet);
}
And some public ints
public class JQueryDataTableParamModel
{
public string sEcho { get; set; }
public string sSearch { get; set; }
public int iDisplayLength { get; set; }
public int iDisplayStart { get; set; }
public int iColumns { get; set; }
public int iSortingCols { get; set; }
public string sColumns { get; set; }
}
I would like to know what I should put at the var Result.
everything is displayed correctly except the link, I tried something like Url.Action but without luck, it doesn't give a link back.
Not very sure what kind of detail data that you want to show, but you can check the method: fnrender or mRender, below is a sample.
"aoColumns": [
{
"sName": "ID",
},
{ "sName": "Student_naam" },
{ "sName": "klas" },
{ "sName": "adres" },
{ "sName": "woonplaats" },
{ "sName": "details",
"mRender": function ( data, type, full ) {
return 'Download';
} }
]
Sorry, I'm a dumbass, I remembered I could put string in the controller with HTML and it would convert it to HTML ->.
var result = from c in displayedStudents select new[] { Convert.ToString(c.studentnr), c.roepnaam, c.klas, c.adres, c.woonplaats, "<a style='font-family:arial' href='" + "../StudentGegevens/index/" + c.studentnr + "' />Details</a>"};
lol, not the brightest person I am, I'm sorry for asking this question.

Resources