Alamofire + Decodable - how turn responseJSON to NSData - alamofire

I'm pretty sure that my problem is easy solving, but I can't find any solution.
So I have Alamofire request and have a trouble with handling data types. I have so many 'printing out' just to check what data I've got step by step.
Alamofire.request(URL, method: .get, headers: headers).responseJSON { response in
switch responseJSON.result {
case .success(let value):
print(type(of: value)) //__NSDictionaryI
print(value)
print(type(of:responseJSON)) //DataResponse<Any>
print(responseJSON) . //SUCCESS: {"billing_addresses" = (...
print(responseJSON.value as Any) . //Optional({...
//print(responseJSON.value as! [[String:Any]]) . //Could not cast value of type '__NSDictionaryI' (0x10b9fb508) to 'NSArray' (0x10b9fb008).
do {
let decoder = JSONDecoder()
let model = try decoder.decode(Info.self, from: value as! Data) //Decode JSON Response Data
print(model.id)
} catch let parsingError {
print("Error", parsingError)
}
Now I have an error: **Could not cast value of type '__NSSingleEntryDictionaryI' (0x10d240f78) to 'NSData' (0x10d241090).**
value of responseJSON is:
(I'm not sure that this value is correct, because when I've check in Postman all strings is doublequoted, and value of "is_default" is true/false, not 0/1. But in the Xcode I've got this in the console. So maybe problem in the responseJSON?..)
And there could be zero address, or several ones.
{
"id": 40128,
"username": "test6",
"email": "test6#on.com",
"billing_addresses": [
{
"address_name": null,
"country_code": "US",
"first_name": "Ted",
"last_name": "Qqqq",
"company_name": "",
"address_line1": "308 Sea Lane",
"address_line2": "",
"city": "QQQQ",
"state": "FL",
"postcode": "32000",
"email_address": "test6#on.com",
"phone_number": "11111111",
"is_default_for_billing": true
}
],
"shipping_addresses": [
{
"address_name": null,
"country_code": "US",
"first_name": "Ted",
"last_name": "Qqqq",
"company_name": "",
"address_line1": "308 Sea Lane",
"address_line2": "",
"city": "QQQQ",
"state": "FL",
"postcode": "32000",
"is_default_for_shipping": true
}
]
}
And here is model
struct Info : Decodable {
let id: Int
let email: String
let username: String
let billing_addresses: Billings
let shipping_addresses: Shippings
}
struct Billings: Decodable{
let address_name: String
let country_code: String
let first_name: String
let last_name: String
let company_name: String
let address_line1: String
let address_line2: String
let city: String
let state: String
let postcode: String
let email_address: String
let phone_number: String
let is_default_for_billing: Bool
}
struct Shippings:Decodable{
let address_name: String
let country_code: String
let first_name: String
let last_name: String
let company_name: String
let address_line1: String
let address_line2: String
let city: String
let state: String
let postcode: String
let is_default_for_shipping: Bool
}
If I try to use SwiftyJSON with value as parameter I have an error that Any couldn't be Data and I really don't know what should I do.

responseJSON.result.value returns the deserialized collection type, in your case a dictionary [String:Any]
To use JSONDecoder you need the raw data which is in response.data
let model = try decoder.decode(Info.self, from: response.data) //Decode JSON Response Data
Consider that you will run into decoding errors: billing_addresses and shipping_addresses are arrays
let billing_addresses: [Billings]
let shipping_addresses: [Shippings] // better name both structs in singular form (Billing, Shipping)
and a few values could be numbers rather than strings.
Anyway it's recommended to use the convertFromSnakeCase key decoding strategy to get rid of the ugly snake_case names.
Edit:
Here are your structs with camelCased names and singular forms, you have to add
decoder.keyDecodingStrategy = .convertFromSnakeCase
struct Info : Decodable {
let id: Int
let email: String
let username: String
let billingAddresses: [Billing]
let shippingAddresses: [Shipping]
}
struct Billing : Decodable {
let addressName: String?
let countryCode, firstName, lastName, companyName: String
let addressLine1, addressLine2, city, state, postcode: String
let emailAddress, phoneNumber: String
let isDefaultForBilling: Bool
}
struct Shipping : Decodable {
let addressName: String?
let countryCode, firstName, lastName, companyName: String
let addressLine1, addressLine2, city, state, postcode: String
let isDefaultForShipping: Bool
}

Related

Iterating through a list containing structs known at compile-time

I'm unable to run the following code because I'm trying to index the struct instead of using a hard-coded name. Other languages do this, but Rust doesn't seem to given its nature of not being object oriented. The official book doesn't even have a good way of doing the following:
struct Address {
number: u32,
city: String,
}
fn print_an_address() {
let Address[0] = {
number: 1,
city: "New York",
}
println!("{}", address[0]);
}
Rust does have this, you're just not using the right syntax. For example:
#[derive(Debug)]
struct Address {
number: u32,
city: String,
}
fn print_an_address() {
let address = [
Address {
number: 1,
city: "New York".to_string(),
}
];
println!("{:?}", address[0]);
}
The local variable address has the array type [Address; 1] here.
(Playground)
You can easily add more elements. Here we add a second element and iterate over the array instead of fetching a specific index. The type of address here has changed to [Address; 2].
#[derive(Debug)]
struct Address {
number: u32,
city: String,
}
fn print_addresses() {
let address = [
Address {
number: 1,
city: "New York".to_string(),
},
Address {
number: 2,
city: "Boston".to_string(),
},
];
for i in address {
println!("{:?}", i);
}
}
(Playground)

Search Algorithm Implementation using NodeJS + MongoDB(or SQL)

There is an application with search input that gives an opportunity to search for contacts by their information stored in database.
For example, I can type 0972133122 Alan and my search engine must return all contacts whose firstname is Alan & whose numbers match 0972133122 string.
Of course, I can just type Alan 0972, for instance, and there must be returned all possible contacts matching this pattern. The query order may be different, so that I can type 0972 Alan Smith, and if there are 2 contacts with Alan names and whose phone numbers start with 0972, then additional Smith clarification should return the only 1 contact.
I suggest built in phone applications for Android make use of this search algorithm:
So that my goal is to achieve similar result, but I do know how to do this. Here my code:
GraphQL query
query contacts {
contacts(input: {
contactQuery: "Alan Smith"
}) {
name {
firstName
lastName
}
}
}
NodeJS query to MongoDB
const conditions = {};
const expr = contactQuery
.split(' ')
.map((contact) => new RegExp(`${contact}`, 'i'))
conditions.$or = [
{ 'firstName': { $in: expr } },
{ 'lastName': { $in: expr } },
{ 'university': { $in: expr } },
{ emails: { $elemMatch: { email: { $in: expr } } } },
{ phones: { $elemMatch: { phone: { $in: expr } } } },
{ socials: { $elemMatch: { id: { $in: expr } } } },
]
const contacts = await this.contacts
.find(conditions, undefined)
.exec()
This works partly, but I receive unwanted documents from MongoDB:
{
contacts: [
{
firstName: "Alan",
lastName: "Smith",
university: "KNTU",
...
},
{
firstName: "Alan",
lastName: "Alderson", // should not be returned
university: "ZNU",
...
},
...
]
}
But I need to get one contact that has strictly Alan firstname and Smith lastname. If it's impossible to do with MongoDB, -- please, provide me an example of SQL query. Any suggestions & solutions will be accepted!
Please, let me know if my question still is not clear.
Firstly, you need to separate out the numbers and words from the search text and then you can create a possible combination of it for an example:
FirstName: Alan, LastName: Smith
FirstName: Smith, LastName: Alan
Using regex you can do this easily and then you can use logical operators of mongodb to create your query like this
Approach 1
db.collection.find({
$or: [
{
$and: [
{
firstName: {
$regex: "Alan",
$options: "i"
}
},
{
lastName: {
$regex: "Smith",
$options: "i"
}
}
]
},
{
$and: [
{
firstName: {
$regex: "Smith",
$options: "i"
}
},
{
lastName: {
$regex: "Alan",
$options: "i"
}
}
]
}
]
})
Here is the link to the playground for you to look at it in action Mongo Playground
Approach 2
Another way is where you concat all the searchable keys into one field and then use regex to filter it out like this
db.collection.aggregate([
{
$addFields: {
text: {
$concat: [
"$firstName",
" ",
"$lastName",
" ",
"$university",
" ",
"$phones"
]
}
}
},
{
$match: {
text: {
$regex: "(?=.*?(0972))(?=.*?(Alan))(?=.*?(Smith))",
$options: "i"
}
}
},
{
$project: {
text: 0
}
}
])
Code to build the query:
let text = "0972 Alan Smith";
let parts = text.split(" ");
let query = parts.map(part => "(?=.*?("+part+"))").join("");
console.log(query);
But you need to check the performance implication of this approach or you can create a view and then query to view to make your query more cleaner
Here is the link to the playground for you to look at it in action Mongo Playground

SwiftUI - Adding locations to data model

I currently have a data model that has an array of venues and I'm trying to add in location information for each venue. I'm running into a problem when I'm defining the struct. Here is an example of the data.
venues: [
Venue (
title: "Holiday",
venueImage: "defaultVenue",
venueDesc: "ipsum lorem",
venueArea: "World East",
coordinate: .init(latitude: -33.852222, longitude: 151.210556),
venueItems: [
venueItem (
id: 101,
title: "Potato Dumpling",
itemURL: "default.png",
productDescription: "Potato Dumpling with Mushroom Sauce",
productPrice: 4.50,
productType: "Food",
newStatus: false,
diningPlan: false,
kidFriendly: true,
vegetarian: false,
glutenFree: false,
featuredProduct: false,
containsAlcohol: false
)])]
And here is the struct
struct Venue: Identifiable {
let id = UUID()
let title : String
let venueImage: String
let venueDesc : String
let venueArea: String
let coordinate: CLLocationCoordinate2D
let venueItems: [venueItem]
init(title: String,
venueImage: String,
venueDesc: String,
venueArea: String,
coordinate: CLLocationCoordinate2D,
venueItems: Array<Any>) {
self.title = title
self.venueDesc = venueDesc
self.venueArea = venueArea
**self.venueItems = [venueItem]**
self.coordinate = coordinate
}
}
The error I'm getting is: Cannot assign value of type '[venueItem].Type' to type '[venueItem]'
struct VenueItem: Identifiable {
var id = UUID()
var title: String
var itemURL: String
var productDescription: String
var productPrice: Float
var productType: String
var newStatus: Bool
var diningPlan: Bool
var kidFriendly: Bool
var vegetarian: Bool
var glutenFree: Bool
var featuredProduct: Bool
var containsAlcohol: Bool
}
struct Venue: Identifiable {
var id = UUID()
var title: String
var venueImage: String
var venueDesc: String
var venueArea: String
var coordinate: CLLocationCoordinate2D
var venueItems: [VenueItem]
}
let venues = [
Venue(
title: "Holiday",
venueImage: "defaultVenue",
venueDesc: "ipsum lorem",
venueArea: "World East",
coordinate: .init(latitude: -33.852222, longitude: 151.210556),
venueItems: [
VenueItem(
title: "Potato Dumpling",
itemURL: "default.png",
productDescription: "Potato Dumpling with Mushroom Sauce",
productPrice: 4.50,
productType: "Food",
newStatus: false,
diningPlan: false,
kidFriendly: true,
vegetarian: false,
glutenFree: false,
featuredProduct: false,
containsAlcohol: false
)
]
)
]

GraphQL, Apollo : Creating an efficient schema

I recently started studying server development with GraphQL and Apollo.
In the code below, the formula for fetching each data is somewhat understandable.
schema.js
const { gql } = require('apollo-server');
const _ = require('lodash');
const onepieces = [
{
"id": "onepiece1",
"title": "원피스 1권",
"price": "1,360",
"desc": "동터오는 모험의 시대"
},
{
"id": "onepiece2",
"title": "원피스 2권",
"price": "1,360",
"desc": "대결 버기 해적단"
}
];
const narutos = [
{
"id": "naruto1",
"title": "나루토 1권",
"price": "1,360",
"desc": "나루토 모험의 시작"
},
{
"id": "naruto2",
"title": "나루토 2권",
"price": "1,360",
"desc": "나루토와 안개마을"
}
];
const typeDefs = gql`
type Onepiece { id: ID, title: String, price: String, desc: String }
type Naruto { id: ID, title: String, price: String, desc: String }
type Query {
onepiece(id: String!): Onepiece,
naruto(id: String!): Naruto,
getOnepieces: [Onepiece],
getNarutos: [Naruto]
}
`;
const resolvers = {
Query: {
onepiece: (parent, args) => _.find(onepieces, {id: args.id}),
naruto: (parent, args) => _.find(narutos, {id: args.id}),
getOnepieces: () => onepieces,
getNarutos: () => narutos
}
};
module.exports = { typeDefs, resolvers };
But It's inefficient code. If the category of comic book increases, I should continue to add the query. So I want to improve More convenient and readable.
For example, I would like to manage the Onepiece and Naruto categories in Comic Book.
How can I improve?
You might start by writing a GraphQL enum of the possible categories.
enum Category { ONEPIECE NARUTO }
Since both kinds of comic books have the same structure, you can have a single GraphQL type to represent them. We'll incorporate the category we just wrote so that you can tell which one is which.
type ComicBook implements Node {
id: ID!
category: Category!
title: String!
price: String!
desc: String!
}
There's a somewhat standard convention for retrieving arbitrary GraphQL objects by their ID; while it comes from Facebook's Relay Javascript client it's not specifically tied to that client, and I'd use it here.
interface Node {
id: ID!
}
type Query {
node(id: ID!): Node
}
This replaces your top-level queries to retrieve specific kinds of books by ID; you could write a query like
{
node(id: "naruto1") {
... on ComicBook { category title price desc }
}
}
Now that you have the category enum, you can also write a single top-level query to return comic books possibly filtered by category
type Query {
comicBooks(category: Category): [ComicBook!]!
}
{
comicBooks(category: ONEPIECE) { id title price desc }
}
There's some corresponding code changes to make this work; I'd probably start by combining the two lists of comic books into one and adding a similar category field there.
Once you've done this, if you add a third category, you need to add it to the enum and add it to the data set, but you should not need to make any other changes to either the code, the GraphQL schema, or the queries.

How to read a subsection from a firebase database

I am using this code to access a Firebase Database, but I am cannot figure out how to read the sub array of strings. (the JSON structure is below)). The code I have returns the top level items, but not the list of strings. Would someone be able to assist with this issue?
Here is my function to read from the DB:
func sizes(userId: String = Auth.auth().currentUser!.uid, success: #escaping ([Sizes]) -> ()) {
let ref = Router.sizes.reference()
let query = ref.queryOrdered(byChild: "name") //userId)
query.observe(.value, with: { snapshot in
var array = [Sizes]()
for child in snapshot.children {
if let size = Mapper<Sizes>().map(JSON: (child as! DataSnapshot).value as! [String : AnyObject]) {
array.append(size)
}
}
success(array)
})
}
My Firebase JSON is as follows:
{
"-SzCat_001": {
"name": "Womans",
"sizeCategories": {
"name": "Pants",
"sizeDescriptor": [
"00",
"0",
"2",
"4",
"6",
"8",
"10",
"12",
"XL"
]
}
}
}
And this is what I get returned?
[0] = {
name = "Womans"
sizeCategories = 0 values {} }
I am trying to figure out how to read the sizeCategories list of strings as a subarray of sizes.
Here is my definition of sizes and sizeCategories:
struct Sizes: Mappable {
var name: String = ""
var sizeCategories = [SizeCategories]()
init() {
}
init?(map: Map) {
}
mutating func mapping(map: Map) {
name <- map["name"]
sizeCategories <- map["sizeCategories"]
}
}
struct SizeCategories: Mappable {
var name: String = ""
var sizeDescriptor = [String]()
init() {
}
init?(map: Map) {
}
mutating func mapping(map: Map) {
name <- map["name"]
sizeDescriptor <- map["sizeDescriptor"]
}
}
Thanks for any help!!!
You're jumping through a lot of hoops to read the data here. You could just let allMyData = snapshot.value as! [String: AnyObject] and know that each internal value is also a [String: AnyObject]. But if you really want to destructure into something more typed with this mapping technique, have a look at your sizes definition:
var sizeCategories = [SizeCategories]()
This says "sizeCategories is an array of SizeCategories type". But your data is not structured as an array, it is a dict:
"sizeCategories": {
"name": "Pants",
"sizeDescriptor": [
"00",
"0",
"2",
"4",
"6",
"8",
"10",
"12",
"XL"
]
}
You need to adjust your definition and mapping method here for this field.