Azure Logic App, parse JSON, but possible null - azure

I want to parse json, based on the following classes:
public class DerModel
{
public string Name { get; set; }
public string Email { get; set; }
}
public class DriverPositiveResultModel
{
public int DriverId { get; set; }
public string DriverName { get; set; }
public string DriverSSN { get; set; }
public string CarrierName { get; set; }
public DerModel DER { get; set; }
}
and the following schema:
{
"properties": {
"CarrierName": {
"type": "string"
},
"DER": {
"properties": {
"Email": {
"type": "string"
},
"Name": {
"type": "string"
}
},
"type": "object"
},
"DriverId": {
"type": "integer"
},
"DriverName": {
"type": "string"
},
"DriverSSN": {
"type": "string"
}
},
"type": "object"
}
but logic allows, that DER can be null. How to set it in the schema?

You need to specify that it can be null:
"type": ["object","null"]
so your code would look like this:
{
"properties": {
"CarrierName": {
"type": "string"
},
"DER": {
"properties": {
"Email": {
"type": "string"
},
"Name": {
"type": "string"
}
},
"type": ["object","null"]
},
"DriverId": {
"type": "integer"
},
"DriverName": {
"type": "string"
},
"DriverSSN": {
"type": "string"
}
},
"type": "object"
}

Related

Can I define an extend field for response component Swagger?

Current, I use #/components/responses/Default response as reuseable properties for all api defines. But some API need to add more a field but not change default response format. So Can I reUse default response and add more field for response
{
"openapi": "3.0.3",
"path": {
"/login": {
"post": {
"responses": {
200: {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/responses/defaultResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas" :{
"responseSchema": {
"type": "object",
"properties": {
"httpCode": { "type": "integer" },
"message": { "type": "string" }
}
}
},
"responses": {
"defaultResponse": { "$ref": "#/components/schemas/responseSchema" }
}
}
}
Above is my swagger spec. but with Login, if success I want to put more a field (token) to return token for client, Can I do it with this or have to manual define schema ?
In OpenAPI version 3, you do this with the allOf keyword. Detail document
{
"openapi": "3.0.3",
"info": {
"title": "Example",
"version": "1.0"
},
"paths": {
"/login": {
"post": {
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"allOf": [
{
"$ref": "#/components/responses/defaultResponse"
},
{
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
}
]
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"responseSchema": {
"type": "object",
"properties": {
"httpCode": {
"type": "integer"
},
"message": {
"type": "string"
}
}
}
},
"responses": {
"defaultResponse": {
"$ref": "#/components/schemas/responseSchema"
}
}
}
}

Elasticsearch NodeJs putIndexTemplate API

I'm using elasticsearch 7.13.3 and I want to call the put index template API from my typescript app. I'm using the package "#elastic/elasticsearch": "7.13.0" but I get error for the composition of the call.
From kibana I can execute without any error:
PUT _component_template/template-xxx2
{
"template": {
"mappings": {
"properties": {
"#timestamp": {
"type": "date"
},
"id": {
"type": "keyword"
},
"value": {
"type": "double",
"coerce": false
}
}
}
}
}
PUT _index_template/index-template-xxx2
{
"index_patterns": ["template-xxx2*"],
"template": {
"settings": {
"number_of_shards": 2
},
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"created_at": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z yyyy"
}
}
},
"aliases": {
"mydata": { }
}
},
"priority": 600,
"composed_of": ["template-xxx2"],
"version": 3,
"_meta": {
"description": "template-xxx2 description"
}
}
and I want do the same from my node app.
The template creation it's ok:
void this.db.clientDb.indices.putTemplate({
name: `template_${this.index}`,
body: {
mappings: {
properties: {
'#timestamp': {
type: 'date'
},
id: {
type: 'keyword'
},
value: {
type: 'double',
coerce: false
}
}
}
}
});
But I can't find the correct overload for the this.db.clientDb.indices.putIndexTemplate({ API.
This gave me errors: (no overloads match this call)
void this.db.clientDb.indices.putIndexTemplate({
name: '',
index_patterns: ["template-xxx2*"], // --> where should I put this property?
body: {
settings: {
number_of_shards: 2
},
mappings: {
_source: {
enabled: true
}
},
aliases: {
mydata: {}
}
},
priority: 500,
composed_of: ['template-xxx2'], // --> where should I put this property?
version: 3,
_meta: {
description: 'template-xxx2 description'
}
});
I want to do this latest script.
Index templates have been overhauled in 7.8. The previous legacy endpoint was called _template and the new one is called _index_template.
You're mixing calls to the old and the new endpoint, i.e. putTemplate calls the old legacy endpoint and putIndexTemplate calls the new one.
Moreover, the whole template definition needs to go inside body, not at the top level of the call parameters.
So here is what you need to do. First, make this call to store the component template:
void this.db.clientDb.cluster.putComponentTemplate({
"name": "template-xxx2",
"body": {
"template": {
"mappings": {
"properties": {
"#timestamp": {
"type": "date"
},
"id": {
"type": "keyword"
},
"value": {
"type": "double",
"coerce": false
}
}
}
}
}
})
Then store the index template with the following call:
void this.db.clientDb.indices.putIndexTemplate({
"name": "index-template-xxx2",
"body": {
"index_patterns": ["template-xxx2*"],
"template": {
"settings": {
"number_of_shards": 2
},
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"created_at": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z yyyy"
}
}
},
"aliases": {
"mydata": { }
}
},
"priority": 600,
"composed_of": ["template-xxx2"],
"version": 3,
"_meta": {
"description": "template-xxx2 description"
}
}
})

Entity Framework Core Explicit Loading how to ignore deeper nested entities

I have a database with the following tables:
User:
public class User
{
public string UserId { get; set; }
public string Name { get; set; }
public Department DefaultDepartment { get; set; }
public ICollection<RoleDepartment> RoleDepartment{ get; set; }
}
Role:
public class Role
{
public int Id { get; set; }
public string Permissions { get; set; }
public ICollection<RoleDepartment> RoleDepartment{ get; set; }
}
RoleDepartment:
public class RoleDepartment
{
public int DepartmentId { get; set; }
public string UserId { get; set; }
public int RoleId { get; set; }
public Department Department { get; set; }
public User User { get; set; }
public Role Role { get; set; }
}
Department
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RoleDepartment> RoleDepartment { get; set; }
}
when i get user data as follow
User user = dbContext.Users
.Single(u => u.UserId == user_id);
dbContext.Entry(user).Reference(u => u.DefaultDepartment).Load();
dbContext.Entry(user).Collection(u => u.RoleDepartment).Load();
I receive too much data
{
"UserId": "***",
"Name": "***",
"DefaultDepartment": {
"Id": "**",
"Name": "***",
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**",
"User": {
"UserId": "***",
"Name": "***",
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**"
}
]
}
}
]
},
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**",
"User": {
"UserId": "***",
"Name": "***",
"DefaultDepartment": {
"Id": "**",
"Name": "***",
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**"
}
]
}
}
},
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**",
"Department": {
"Id": "**",
"Name": "***",
"RoleDepartment": []
},
"User": {
"UserId": "***",
"Name": "***",
"DefaultDepartment": {
"Id": "**",
"Name": "***",
"RoleDepartment": []
}
}
}
]
}
I want something like this:
{
"UserId": "***",
"Name": "***",
"DefaultDepartment": {
"Id": "**",
"Name": "***",
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**"
}
]
},
"RoleDepartment": [
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**",
},
{
"DepartmentId": "**",
"UserId": "***",
"RoleId": "**"
}
]
}
There is a way to ignore the nested User and Department entities?
I want to ignore auto-loaded data when I use explicit-loading.
Did I miss something?
Thanks
This seems like a self referencing loop. If you are not using NewtonsoftJson install it using,
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
You can then edit your startup.cs where you add in Newtonsoft to configure the ReferenceLoopHandling
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
There is another way to avoid reference loops and that is to tell the serializer to not serialize a property at all. In both Newtonsoft.Json and System.Text.Json there is an attribute called JsonIgnore,
public class RoleDepartment
{
public int DepartmentId { get; set; }
public string UserId { get; set; }
public int RoleId { get; set; }
public Department Department { get; set; }
[JsonIgnore]
public User User { get; set; }
public Role Role { get; set; }
}
But the recomended way is to create DTOs/ViewModels and map your Entities with them. Refer this for more info.
Edit:
You can stop reference loops for this case only as follows.
User user = dbContext.Users
.Single(u => u.UserId == user_id);
dbContext.Entry(user).Reference(u => u.DefaultDepartment).Load();
dbContext.Entry(user).Collection(u => u.RoleDepartment).Load();
var Settings = new Newtonsoft.Json.JsonSerializerSettings
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(user, user.GetType().BaseType, Settings);
Also you can create an anonymous object as follows and return it as well.
dbContext.Users.Select(x => new { Prop1 = x.Property1, Prop2 = x.Property2 });

Swagger.json generating with incorrect case "type": "String"

In troubleshooting this problem we found that swagger.json contained incorrect case for
"type": "String"
in the generated code
"/api/FrameLookUp": {
"post": {
"tags": [
"Frame"
],
"operationId": "FrameLookup",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "header",
"name": "Authorization",
"description": "access token",
"required": true,
"type": "String"
},
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/FrameRequest"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/FrameResponse"
}
}
}
}
}
}
I have the following ISchemaFilter
public class SwaggerEnumFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");
if (context == null)
throw new ArgumentNullException("context");
if (context.Type.IsEnum)
model.Extensions.Add(
"x-ms-enum",
new OpenApiObject
{
["name"] = new OpenApiString(context.Type.Name),
["modelAsString"] = new OpenApiBoolean(false)
}
);
}
}
What could be causing this?
It turned out to be that I was using
services.AddSwaggerGen(c =>
{
c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
and inside the class I had
Schema = new OpenApiSchema() { Type = "String" },
it should have had "string" as lower case.

response.Content.ReadAsStringAsync no reading all data

I have an azure function that calls a Rest API with basic authentication.
The respone form the server is ok but I have a problem with only receiving partial data back from the response - some fields are coming back as null.
I am using httpclient to make the rest API call. Here is my code:
using (var client = new HttpClient())
{
var webUrl = "https://api.livechatinc.com/chats/XXXXXX";
client.BaseAddress = new Uri(webUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = "XXXXXXXXXX";
var password = "XXXXXXXXX";
var base64String = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{password}"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64String);
HttpResponseMessage response = await client.GetAsync(webUrl);
response.EnsureSuccessStatusCode();
//Only getting partial information
string jsonString = await response.Content.ReadAsStringAsync();
//Deserialise JSON
Chat responseData = JsonConvert.DeserializeObject<Chat>(jsonString);
}
When I run my azure function debugger I can prove that I get null fields for the URL data that I am expecting.
Notice that responseData field shows a null value for ChatStartUrl after desrialisation.
This is because the field is not being returned from the response content.
I have made sure it is not my data contract and JSON.net deserialisation. My data contract is :
public class Chat
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("tickets")]
public Ticket[] Tickets { get; set; }
[JsonProperty("visitor_name")]
public string VisitorName { get; set; }
[JsonProperty("visitor_id")]
public string VisitorId { get; set; }
[JsonProperty("visitor_ip")]
public string VisitorIp { get; set; }
[JsonProperty("visitor")]
public Visitor Visitor { get; set; }
[JsonProperty("agents")]
public Agent[] Agents { get; set; }
[JsonProperty("supervisors")]
public object[] Supervisors { get; set; }
[JsonProperty("rate")]
public string Rate { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
[JsonProperty("chat_start_url")]
public Uri ChatStartUrl { get; set; }
[JsonProperty("referrer")]
public Uri Referrer { get; set; }
[JsonProperty("group")]
public long[] Group { get; set; }
[JsonProperty("started")]
public string Started { get; set; }
[JsonProperty("custom_variables")]
public object[] CustomVariables { get; set; }
[JsonProperty("pending")]
public bool Pending { get; set; }
[JsonProperty("tags")]
public object[] Tags { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
[JsonProperty("greeting")]
public Greeting Greeting { get; set; }
[JsonProperty("messages")]
public Event[] Messages { get; set; }
/* [JsonProperty("prechat_survey")]
public PrechatSurvey[] PrechatSurvey { get; set; }*/
[JsonProperty("events")]
public Event[] Events { get; set; }
[JsonProperty("engagement")]
public string Engagement { get; set; }
[JsonProperty("started_timestamp")]
public long StartedTimestamp { get; set; }
[JsonProperty("ended_timestamp")]
public long EndedTimestamp { get; set; }
[JsonProperty("ended")]
public string Ended { get; set; }
}
public class Agent
{
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("ip")]
public string Ip { get; set; }
}
public class Event
{
[JsonProperty("author_name", NullValueHandling = NullValueHandling.Ignore)]
public string AuthorName { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("message_json", NullValueHandling = NullValueHandling.Ignore)]
public string MessageJson { get; set; }
[JsonProperty("date")]
public string Date { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("agent_id", NullValueHandling = NullValueHandling.Ignore)]
public string AgentId { get; set; }
[JsonProperty("user_type")]
public string UserType { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("welcome_message", NullValueHandling = NullValueHandling.Ignore)]
public bool? WelcomeMessage { get; set; }
[JsonProperty("event_type", NullValueHandling = NullValueHandling.Ignore)]
public string EventType { get; set; }
}
public class Greeting
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class Ticket
{
[JsonProperty("id")]
public string Id { get; set; }
}
public class Visitor
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("ip")]
public string Ip { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("country_code")]
public string CountryCode { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
[JsonProperty("user_agent")]
public string UserAgent { get; set; }
}
What's interesting is that the rest api works fine in Postman and I can get all data back.
This is what I get from the Postman response
{
"type": "chat",
"id": "PPTE7XI3AQ",
"tickets": [
{
"id": "DJWKT"
}
],
"visitor_name": "Rupinder Kaur",
"visitor_id": "S1552009602.e395581450",
"visitor_ip": "49.183.59.243",
"visitor": {
"id": "S1552009602.e395581450",
"name": "Rupinder Kaur",
"email": "rupinder#creativa.com.au",
"ip": "49.183.59.243",
"city": "Abbotsford",
"region": "Victoria",
"country": "Australia",
"country_code": "AU",
"timezone": "Australia/Victoria",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
},
"agents": [
{
"display_name": "David",
"email": "david.sender#wiise.com",
"ip": "203.30.93.14"
}
],
"supervisors": [],
"rate": "not_rated",
"duration": 357,
"chat_start_url": "https://wiise.com/au/explore/detailed-accounting/?utm_source=googlewiise&utm_medium=paidsearch&utm_campaign=Wiise&gclid=EAIaIQobChMI3ZrLuqG14QIVBR2PCh0VIAb7EAAYASAAEgKkWPD_BwE",
"referrer": "https://www.google.com/",
"group": [
0
],
"started": "Thu, 04/04/19 12:25:43 pm",
"custom_variables": [],
"pending": false,
"tags": [],
"timezone": "Australia/Sydney",
"greeting": {
"id": 7991,
"name": "Invite after 360 seconds"
},
"messages": [
{
"author_name": "David",
"text": "Hi there :) \n\nThank you for checking out our website, how can I help?",
"message_json": "",
"date": "Thu, 04/04/19 12:25:43 pm",
"timestamp": 1554341143,
"agent_id": "david.sender#wiise.com",
"user_type": "agent",
"type": "message",
"welcome_message": true
},
{
"author_name": "Rupinder Kaur",
"text": "hi there",
"message_json": "",
"date": "Thu, 04/04/19 12:25:54 pm",
"timestamp": 1554341154,
"user_type": "visitor",
"type": "message"
},
{
"author_name": "Rupinder Kaur",
"text": "I would like to trial it",
"message_json": "",
"date": "Thu, 04/04/19 12:26:01 pm",
"timestamp": 1554341161,
"user_type": "visitor",
"type": "message"
},
{
"author_name": "Rupinder Kaur",
"text": "I am mainly looking for cashflow reports",
"message_json": "",
"date": "Thu, 04/04/19 12:26:25 pm",
"timestamp": 1554341185,
"user_type": "visitor",
"type": "message"
}
],
"prechat_survey": [
{
"key": "Name:",
"value": "xxxxxx",
"id": "2001"
},
{
"key": "E-mail:",
"value": "xxxxxx",
"id": "2002"
}
],
"events": [
{
"author_name": "David",
"text": "Hi there :) \n\nThank you for checking out our website, how can I help?",
"message_json": "",
"date": "Thu, 04/04/19 12:25:43 pm",
"timestamp": 1554341143,
"agent_id": "david.sender#wiise.com",
"user_type": "agent",
"type": "message",
"welcome_message": true
},
{
"author_name": "XXXXXX",
"text": "XXXXXXXXXX",
"message_json": "",
"date": "Thu, 04/04/19 12:25:54 pm",
"timestamp": 1554341154,
"user_type": "visitor",
"type": "message"
},
{
"author_name": "XXXXXX",
"text": "XXXXXXXXXX",
"message_json": "",
"date": "Thu, 04/04/19 12:26:01 pm",
"timestamp": 1554341161,
"user_type": "visitor",
"type": "message"
},
{
"author_name": "XXXXXX",
"text": "XXXXXXXXXX",
"message_json": "",
"date": "Thu, 04/04/19 12:26:25 pm",
"timestamp": 1554341185,
"user_type": "visitor",
"type": "message"
},
{
"text": "Rupinder Kaur left the chat.",
"date": "Thu, 04/04/19 12:31:40 pm",
"timestamp": 1554341500,
"type": "event",
"event_type": "closed",
"user_type": "visitor"
}
],
"engagement": "auto_invite",
"started_timestamp": 1554341143,
"ended_timestamp": 1554341500,
"ended": "Thu, 04/04/19 12:31:40 pm"}
I have tried deserialisaing the contents returned from Postman and I get all the data with no null fields
//This works
var testJSON = System.IO.File.ReadAllText(#"C:\temp\ChatSchema.json");
Chat responseData = JsonConvert.DeserializeObject<Chat>(testJSON);
So I suspect that the Content.ReadAsStringAsync function is not owrking as expected.
I tried the following and still had the same issue:
var buffer = await response.Content.ReadAsByteArrayAsync();
var responseString = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
string content = responseString;
Chat des = JsonConvert.DeserializeObject<Chat>(content);
To read in the raw text and then de-serialise it to the model class. I also had to change the serialisation routine to save as 'UTF-8'.
You could refer to the code as below:
var stream = response.Content.ReadAsStreamAsync().Result;
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
string content = text;
string des = JsonConvert.DeserializeObject<Chat>(content);
Just solved my problem !
I had to add a custom header since LiveChat required it:
client.DefaultRequestHeaders.Add("X-API-Version", "2");
Now I am getting all the info including Uri data coming through !
Thanks for all responses.

Resources