parsing invalid JSON swift 5 - ios

I have an invalid json comping from external api:
{
status: 'ok',
pills: [{
id: 1,
name: "Мезим форте",
img: "https://cloud.fdoctor.ru/test_task/static/mezim.jpg",
desription: "Перед завтраком",
dose: "По таблетке"
},
{
id: 2,
name: "Bioderma",
img: "https://cloud.fdoctor.ru/test_task/static/bioderma.jpg",
desription: "Во время еды"
dose: "По 3 глотка"
},
{
id: 3,
name: "Гексорал, Аэрозоль"
img: "https://cloud.fdoctor.ru/test_task/static/gecsoral.jpg",
desription: "При острых болях"
dose: "По 3 пшика"
},
{
id: 4,
name: "Тантум Верде, спрей"
img: "https://cloud.fdoctor.ru/test_task/static/tantum.jpg",
desription: "Каждые 4 часа в течении 7 дней"
dose: "По таблетке"
}
]
}
Is there a way to parse it with codable protocol?
Fixing it on API is not an option.

You can use the following reg ex replacements to clean the string and make it json compliant
//Surround keys with quotes
let firstStep = input.replacingOccurrences(of: #"\s(\w+):{1}"#,
with: #""$1":"#,
options: .regularExpression)
//Fix status value
let json = firstStep.replacingOccurrences(of: "'", with: "\"")

Related

Use If condition in Karate to extract values

I have the following JSON response -
{
"type": "StudentSchema",
"version": 1,
"students": [
{
id: 1,
name: "John",
roll: "1234"
},
{
id: 2,
name: "David",
roll: "4434"
}
]
}
Then how can I extract the array in Karate with name John to do further validation?
e.g. I want to say if name == John then save the id
I am trying below but it does not seem to work -
* def userId = get[0] response $[?(#students.name == 'John')].id
* match userId == 2
Let say your JSON is
MyJson = {
"type": "StudentSchema",
"version": 1,
"students": [
{
id: 1,
name: "John",
roll: "1234"
},
{
id: 2,
name: "David",
roll: "4434"
}
]
}
Now as you want to get the ID for the student whose name is john you can get it by using JSON path
* def JSONpath = '$..students[?(#.name=='John')].id'
* def userId = karate.jsonPath(MyJson,JSONpath)
It will give you an array of ID which satisfy the json path condition and you can do your assertion from that.

How to create loop within a JSON request object?

I need to create multiple "items" to be used within a json request .
Here's a request that works:
customs_info = EasyPost::CustomsInfo.create(
eel_pfc: 'NOEEI 30.37(a)',
customs_certify: true,
customs_signer: "first_name last_name",
contents_type: 'merchandise',
contents_explanation: '',
restriction_type: 'none',
restriction_comments: '',
# non_delivery_option: 'abandon',
customs_items: [
{
description: "asdf",
quantity: 1,
weight: 23,
value: 23,
# hs_tariff_number: '654321',
origin_country: 'US'
},
{
description: "1234568",
quantity: 1,
weight: 23,
value: 23,
# hs_tariff_number: '654321',
origin_country: 'US'
}
]
)
What I need is to not need to manually set the customs_items.
I tried:
customs_info = EasyPost::CustomsInfo.create(
eel_pfc: 'NOEEI 30.37(a)',
customs_certify: true,
customs_signer: "#{shipping_address.shipping_address_final.first_name} #{shipping_address.shipping_address_final.last_name}",
contents_type: 'merchandise',
contents_explanation: '',
restriction_type: 'none',
restriction_comments: '',
# non_delivery_option: 'abandon',
customs_items: [
vendor_line_items.map do |li|
{
description: "#{li.shop_product.product.item.title}",
quantity: li.quantity,
weight: li.shop_product.product.weight,
value: li.shop_product.price,
# hs_tariff_number: '654321',
origin_country: 'US'
}
end
]
)
Error Statement: Parameters to create Custom Item(s) invalid or missing
How can I create the loop to work with the JSON request and work like the first example that works manually?
If you remove the [] that is surrounding the vendor_line_itmes.map code, you will be good to go.
customs_info = EasyPost::CustomsInfo.create(
# ...
customs_items: vendor_line_items.map do |li|
{
description: "#{li.shop_product.product.item.title}",
quantity: li.quantity,
# ...
}
end
)
The map operation returns an array so the json you are currently generating would look like (note the array of arrays in customs_info):
{
"eel_pfc": "NOEEI 30.37(a)",
...
"customs_info": [
[
{
"description": "...",
"quantity": 5,
...
}
]
]
}

Different row data in Nested Table Row

I am using Ant Design for my project. I have a scene where i should use Ant Design Nested Table where in every row opens new nested Table to show data. I am not able to show different data for each row. It is showing same data in all Nested rows
This is what i am using
https://ant.design/components/table/#components-table-demo-nested-table
Code is as such from Official Doc
Expecting to show different data in different nested row items
Inside expandedrow function you can pass a row parameter. Based on the row you can render your own table.
https://codesandbox.io/s/34w7km6o11
In the above sample, you can check how i rendered different data based on that particular row.
I used ternary operator, You can write your own condition
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table } from "antd";
const columns = [
{ title: "Name", dataIndex: "name", key: "name" },
{ title: "Age", dataIndex: "age", key: "age" },
{ title: "Address", dataIndex: "address", key: "address" },
{
title: "Action",
dataIndex: "",
key: "x",
render: () => Delete
}
];
const data = [
{
key: 1,
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park",
description:
"My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park."
},
{
key: 2,
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park",
description:
"My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park."
},
{
key: 3,
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park",
description:
"My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park."
}
];
const data1 = [
{
key: 1,
name: "I am diff",
age: 32,
address: "New York No. 1 Lake Park",
description:
"My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park."
},
{
key: 2,
name: "yes",
age: 42,
address: "London No. 1 Lake Park",
description:
"My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park."
},
{
key: 3,
name: "no",
age: 32,
address: "Sidney No. 1 Lake Park",
description:
"My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park."
}
];
const data2 = [
{
key: 1,
name: "hello",
age: 32,
address: "New York No. 1 Lake Park",
description:
"My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park."
},
{
key: 2,
name: "hi",
age: 42,
address: "London No. 1 Lake Park",
description:
"My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park."
},
{
key: 3,
name: "test",
age: 32,
address: "Sidney No. 1 Lake Park",
description:
"My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park."
}
];
const expandedRow = row => {
console.log(row);
let inTable = row.key == 1 ? data1 : row.key == 2 ? data2 : data;
return <Table columns={columns} dataSource={inTable} pagination={false} />;
};
ReactDOM.render(
<Table columns={columns} expandedRowRender={expandedRow} dataSource={data} />,
document.getElementById("container")
);
I have a different approach to this problem, I have been looking around in other posts and have not found this solution, I hope it helps:
import React from "react";
import "antd/dist/antd.css";
import { Table } from "antd";
import { fakeFirstLevelData } from
'../fakeDataBase/fakeFirstLevelData'
const firstLevelColumns = [
{
title: 'ID',
dataIndex: 'id_tx',
key: 'ID_TX'
},
{
title: 'Amount',
dataIndex: 'amount',
key: 'amount'
},
{
title: 'Currency',
dataIndex: 'currency',
key: 'currency'
},
]
const secondLevelColumns = [
{
title: 'First name from',
dataIndex: 'firstname_from',
key: ''
},
{
title: 'first name to',
dataIndex: 'firstname_to',
key: ''
},
{
title: 'Date ',
dataIndex: 'date',
key: ''
},
]
const firstExpandedRow = (record, index, indent, expanded) => {
let data = []
data.push(record.secondLevel)
return (
<Table
rowKey={record => record.cardholderid}
columns={secondLevelColumns}
dataSource={data}
// expandable={{ expandedRowRender: secondExpandedRow }}
pagination={false}
/>
)
}
return (
<div className='container mt-40 mb-40 overflow-x-auto
tableContainer'>
<Table
dataSource={fakeFirstLevelData}
columns={firstLevelColumns}
rowKey={record => record.id_tx}
loading={fakeFirstLevelData ? false : true}
pagination={false}
expandable={{
expandedRowRender: firstExpandedRow,
defaultExpandAllRows: false
}}
/>
</div>
)
This is my fake data , its similar to call a API:
export const fakeFirstLevelData = [
{
id: '1199343457',
amount: '127,45',
currency: 'EUR',
secondLevel: {
firstnameFrom: 'Antonio',
firstnameTo: 'Juan',
date: '2024/12/12'
}
},
{
id: '11993453458',
amount: '1',
currency: 'EUR',
secondLevel: {
firstnameFrom: 'Carlos',
firstnameTo: 'Estefanía',
date: '2024/12/12'
}
}
]
This way I have a json with different levels of information and in each row I can show N fields and by expanding the rows I can show more information of the same row.
make children data with state
then pass it to the expan function
write the parameter with free text
then inside nested table write data[expan.key].children2 inside datasource of nested table.
data[expan.key].children2 is just free text you can change with other. thank you

active model serializer flat structure

I'm bulding my api server for my React/Redux app, where i need some flat response from server to manage and reduce my state.
For example, when i have this response:
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
How can i make it looks like:
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
Best feature is what each key is articles/users id, so i can easily get it from the response and merge it in my front-end app.
You can achieve this with AMS, but you will have to write a custom adapter, as none of the stock ones provide this exact format.
JSON API (and the corresponding AMS JsonApi adapter) solve this issue, but the format is slightly different from the one you want.

How do I use .map to parse response when response has inconsistent values?

So I'm using the yelp API, and after I make a GET request I get back a response of businesses. In order to work with that response I'm using .map
Example:
mappedResults = yelpSearch.businesses.map {|l| {id: l.id, name: l.name, categories:l.categories, rating: l.rating, review_count: l.review_count, url: l.url, phone: l.phone}}
My problem is that sometimes l.phone is not returned for some records in the response, and I get the error:
undefined method `phone' for #<BurstStruct::Burst:0x007fba47c7a228>
My question is how do I refactor this code so that if a record doesn't have phone it will either leave it null (or worst cast empty string)
Any help is appreciated
JSON structure is as such for each business in the response
{
region: {
span: {
latitude_delta: 0,
longitude_delta: 0
},
center: {
latitude: 38.054117,
longitude: -84.439002
}
},
total: 23,
businesses: [
{
is_claimed: false,
rating: 5,
mobile_url: "http://m.yelp.com/biz/vineyard-community-church-lexington",
rating_img_url: "http://s3-media1.ak.yelpcdn.com/assets/2/www/img/f1def11e4e79/ico/stars/v1/stars_5.png",
review_count: 2,
name: "Vineyard Community Church",
snippet_image_url: "http://s3-media4.ak.yelpcdn.com/photo/VoeMtbk7NRFi6diksSUtOQ/ms.jpg",
rating_img_url_small: "http://s3-media1.ak.yelpcdn.com/assets/2/www/img/c7623205d5cd/ico/stars/v1/stars_small_5.png",
url: "http://www.yelp.com/biz/vineyard-community-church-lexington",
phone: "8592582300",
snippet_text: "I have been a member of Vineyard Community Church since 2004. Here you will find a modern worship service with a full band, witty speakers who teach...",
image_url: "http://s3-media3.ak.yelpcdn.com/bphoto/D71eikniuaHjdOC8DB6ziA/ms.jpg",
categories: [
[
"Churches",
"churches"
]
],
display_phone: "+1-859-258-2300",
rating_img_url_large: "http://s3-media3.ak.yelpcdn.com/assets/2/www/img/22affc4e6c38/ico/stars/v1/stars_large_5.png",
id: "vineyard-community-church-lexington",
is_closed: false,
location: {
city: "Lexington",
display_address: [
"1881 Eastland Pwky",
"Lexington, KY 40505"
],
geo_accuracy: 8,
postal_code: "40505",
country_code: "US",
address: [
"1881 Eastland Pwky"
],
coordinate: {
latitude: 38.054117,
longitude: -84.439002
},
state_code: "KY"
}
}
]
}
If you're using Rails 4.0 or newer, the #presence method is really helpful for this. You would use it like this:
mappedResults = yelpSearch.businesses.map {|l| {id: l.id.presence, #... etc
or like this
mappedResults = yelpSearch.businesses.map {|l| {id: l.id.presence || "default id", # ...
Update
Reading your code again, #presence might not work in this case, since the method isn't defined. Here's a longer (uglier) snippet that should work:
mappedResults = yelpSearch.businesses.map do |l|
id: l.respond_to(:id) ? l.id : "default id",
# ... other properties
end
Update from OP
This worked - thank you! Note I had to tweak syntax a bit to respond_to?('method_name')
mappedResults = yelpSearch.businesses.map {|l|
{
name: l.respond_to?("name") ? l.name : "nameless",
rating: l.respond_to?("rating") ? l.rating : "unrated",
# ... other properties
}}

Resources