Creating a body for Alamofire POST request Swift 4

Hello everyone!


I need help with creating a custom body when sending POST request with Alamofire.

I'm sending to API products. There are two types of products. First type has just quantity, second one - different quantities(

size_id
) and quantities that match each
size_id
.


Final body should look like:


"factory_id": "1"

"order_products[0][product_id]": "1"
"order_products[0][size_id]": "2"
"order_products[0][quantity]": "10"

"order_products[1][product_id]": "1"
"order_products[1][size_id]": "3"
"order_products[1][quantity]": "10"

"order_products[1][product_id]": "2"
"order_products[1][size_id]": "2"
"order_products[1][quantity]": "10"

"order_products[2][product_id]": "3"
"order_products[2][quantity]": "10"


Here's what I achieved so far:


var createOrderBody = [String: Any]()
let productIds = ["1", "2", "3"]
var body = [String: Any]()
var quantity = ["1" : "10", "2": "10"]
var noIdQuantity = ["10"]
var finalBody = [String: Any]()

func formBody(products: String, factoryId: String, productId: String, size_id: String, quantity: String) -> [String: Any] {

  createOrderBody["factory_id"] = factoryId
  createOrderBody["order_products[\(products)][product_id]"] = productId
  createOrderBody["order_products[\(products)][size_id]"] = size_id
  createOrderBody["order_products[\(products)][quantity]"] = quantity

  return createOrderBody
}

for (index, value) in productIds.enumerated() {

  for (id, size) in quantity {
  print(id)
  print(size)
  body = formBody(products: String(index), factoryId: "1", productId: String(value), size_id: id, quantity: size)
  print("Body quantity - ", body)
  }
}


And the result I have is:


"factory_id": "1",

"order_products[0][product_id]": "1"
"order_products[0][size_id]": "2", 
"order_products[0][quantity]": "10",

"order_products[1][product_id]": "2",
"order_products[1][size_id]": "2",  
"order_products[1][quantity]": "10",

"order_products[2][product_id]": "3",
"order_products[2][size_id]": "2", 
"order_products[2][quantity]": "10",


As you can see, I have almost achieved desired result, but the problem is that it is adding only last element of

quantity
dictionary and omits other values. Also, I don't know how to add quantity to the product, that doesn't have
size_id


Also, I know that it is not a good practice to place

for in
loop inside other
for in
loop but I'm new to development and this is the best idea that I have came up with.


Would be grateful for any help with this issue, as I've been battling with it almost for a week right now.

Many thanks and have a nice weekends!

Accepted Reply

So, product with id - 1 can have: var quantity = ["1" : "10", "2": "10"] , same goes to product with id - 2 - var quantity = ["1" : "10", "2": "10"] , and for instance, product with id - 3 can be like var quantity = ["1" : "15", "2": "20"], last possible case is product with let's say id - 4, where it can have only quantity as "10" and that's all.


Seems each product with id needs to hold its own `quantity` separately.


You can define a struct like this:

struct Product {
    let id: String
    let quantities: [(sizeId: String, quantity: Int)]?
    let noIdQuantity: Int?
    
    init(id: String, quantities: [(sizeId: String, quantity: Int)]) {
        self.id = id
        self.quantities = quantities
        self.noIdQuantity = nil
    }
    
    init(id: String, quantity: Int) {
        self.id = id
        self.quantities = nil
        self.noIdQuantity = quantity
    }
}


With the struct above, you just need only one input variable and one output variable:

// Define your input `product with id` as an Array of `Product`
let products = [
    Product(id: "1", quantities: [("1", 10), ("2", 10)]),
    Product(id: "2", quantities: [("1", 10), ("2", 10)]),
    Product(id: "3", quantities: [("1", 15), ("2", 20)]),
    Product(id: "4", quantity: 10),
]
// Output dictionary
var body = [String: Any]()


To make entries for a single Product into a Dictionary:

extension Product {
    func formBody(_ index: inout Int, into body: inout [String: Any]) {
        if let quantities = self.quantities {
            for (sizeId, quantity) in quantities {
                body["order_products[\(index)][product_id]"] = self.id
                body["order_products[\(index)][size_id]"] = sizeId
                body["order_products[\(index)][quantity]"] = quantity
                index += 1
            }
        }
        if let quantity = self.noIdQuantity {
            body["order_products[\(index)][product_id]"] = self.id
            body["order_products[\(index)][quantity]"] = quantity
            index += 1
        }
    }
}


And use them as follows:

var index = 0
body["factory_id"] = "1"
for product in products {
    product.formBody(&index, into: &body)
}
print("Body quantity - ", body)
body.sorted {$0.key < $1.key}.forEach{print("\($0.key)=\($0.value)")} //For showing readable result, not for Alammofire body


Result:

Body quantity - ["order_products[4][quantity]": 15,"order_products[5][product_id]": "3", "order_products[3][size_id]": "2", "order_products[5][size_id]": "2", "order_products[5][quantity]": 20, "order_products[0][product_id]": "1", "order_products[4][size_id]": "1", "order_products[2][size_id]": "1", "order_products[2][quantity]": 10, "order_products[3][product_id]": "2", "order_products[0][size_id]": "1", "order_products[1][quantity]": 10, "order_products[2][product_id]": "2", "order_products[3][quantity]": 10, "order_products[6][quantity]": 10, "order_products[1][size_id]": "2", "order_products[6][product_id]": "4", "order_products[0][quantity]": 10, "order_products[1][product_id]": "1", "order_products[4][product_id]": "3", "factory_id": "1"]

factory_id=1

order_products[0][product_id]=1

order_products[0][quantity]=10

order_products[0][size_id]=1

order_products[1][product_id]=1

order_products[1][quantity]=10

order_products[1][size_id]=2

order_products[2][product_id]=2

order_products[2][quantity]=10

order_products[2][size_id]=1

order_products[3][product_id]=2

order_products[3][quantity]=10

order_products[3][size_id]=2

order_products[4][product_id]=3

order_products[4][quantity]=15

order_products[4][size_id]=1

order_products[5][product_id]=3

order_products[5][quantity]=20

order_products[5][size_id]=2

order_products[6][product_id]=4

order_products[6][quantity]=10

Replies

Could you show what you get exactly with the following print:


print(id)

print(size)

body = formBody(products: String(index), factoryId: "1", productId: String(value), size_id: id, quantity: size)

print("Body quantity - ", body)


I see nowhere "Body quantity - "

When you say this is the result you get: result of what, where ?


Looking at you loop:


  1. for (index, value) in productIds.enumerated() {
  2. for (id, size) in quantity {
  3. print(id)
  4. print(size)
  5. body = formBody(products: String(index), factoryId: "1", productId: String(value), size_id: id, quantity: size)
  6. print("Body quantity - ", body)
  7. }
  8. }


At line 1, you will enumerate index, value on 3 pairs:

0, "1"

1, "2"

2, "3"


Then for each you will loop through quantities, with just 2 values for (id, size)

id 2 size 10

id 1 size 10

Note: size is always 10 ?


So, at line 4, you will have the following

0, "1"

id 2 size 10

id 1 size 10

1, "2"

id 2 size 10

id 1 size 10

2, "3"

id 2 size 10

id 1 size 10


Then you build body


0, "1"

id 2 size 10

Body quantity - ["order_products[0][size_id]": "1", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "factory_id": "1"]

id 1 size 10

Body quantity - ["order_products[0][size_id]": "2", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "factory_id": "1"]


1, "2"

id 2 size 10

Body quantity - ["factory_id": "1", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[1][quantity]": "10", "order_products[0][size_id]": "2", "order_products[1][size_id]": "1", "order_products[1][product_id]": "2"]

id 1 size 10

Body quantity - ["factory_id": "1", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[1][quantity]": "10", "order_products[0][size_id]": "2", "order_products[1][size_id]": "2", "order_products[1][product_id]": "2"]


2, "3"

id 2 size 10

Body quantity - ["factory_id": "1", "order_products[2][size_id]": "1", "order_products[2][quantity]": "10", "order_products[2][product_id]": "3", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[1][quantity]": "10", "order_products[0][size_id]": "2", "order_products[1][size_id]": "2", "order_products[1][product_id]": "2"]

id 1 size 10

Body quantity - ["factory_id": "1", "order_products[2][size_id]": "2", "order_products[2][quantity]": "10", "order_products[2][product_id]": "3", "order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[1][quantity]": "10", "order_products[0][size_id]": "2", "order_products[1][size_id]": "2", "order_products[1][product_id]": "2"]


What do you do with it ? How do you build finalBody ?


What you get is the last value of body,

"factory_id": "1",

"order_products[2][size_id]": "2",

"order_products[2][quantity]": "10",

"order_products[2][product_id]": "3",

"order_products[0][quantity]": "10",

"order_products[0][product_id]": "1",

"order_products[1][quantity]": "10",

"order_products[0][size_id]": "2",

"order_products[1][size_id]": "2",

"order_products[1][product_id]": "2"


but you have lost the previous ones, notably the one created at case 1, "2"


So, you should store body in finalBody


But with disctionary, you will not get 2 records as

"order_products[1][product_id]": "1"

"order_products[1][size_id]": "3"

"order_products[1][quantity]": "10"


"order_products[1][product_id]": "2"

"order_products[1][size_id]": "2"

"order_products[1][quantity]": "10"


you use the same key, with different values, so you erase the first value you stored.


For finalBody, you should use an array of dictionaries.


So at the end:


var createOrderBody = [String: Any]()
let productIds = ["1", "2", "3"]
var body = [String: Any]()
var quantity = ["1" : "10", "2": "10"]
var noIdQuantity = ["10"]
var finalBody = [[String: Any]]()     // An array of dictionaries

func formBody(products: String, factoryId: String, productId: String, size_id: String, quantity: String) -> [String: Any] {
   
    createOrderBody["factory_id"] = factoryId
    createOrderBody["order_products[\(products)][product_id]"] = productId
    createOrderBody["order_products[\(products)][size_id]"] = size_id
    createOrderBody["order_products[\(products)][quantity]"] = quantity
   
    return createOrderBody
}

for (index, value) in productIds.enumerated() {
    print("\nindex, value", index, value)
    for (id, size) in quantity {
        print("id", id)
        print("size", size)
        body = formBody(products: String(index), factoryId: "1", productId: String(value), size_id: id, quantity: size)
        print("Body quantity - ", body)
            finalBody.append(body)
    }
}
print("\nfinalBody", finalBody)

and you get finalBody


finalBody [[

"order_products[0][size_id]": "2",

"order_products[0][product_id]": "1",

"factory_id": "1",

"order_products[0][quantity]": "10"],



["order_products[0][size_id]": "1",

"order_products[0][product_id]": "1",

"factory_id": "1",

"order_products[0][quantity]": "10"],



["order_products[0][size_id]": "1",

"order_products[0][quantity]": "10",

"order_products[0][product_id]": "1",

"order_products[1][product_id]": "2",

"factory_id": "1",

"order_products[1][size_id]": "2",

"order_products[1][quantity]": "10"],


["order_products[0][size_id]": "1",

"order_products[0][quantity]": "10",

"order_products[0][product_id]": "1",

"order_products[1][product_id]": "2",

"factory_id": "1",

"order_products[1][size_id]": "1",

"order_products[1][quantity]": "10"],



["order_products[0][size_id]": "1",

"order_products[0][quantity]": "10",

"order_products[0][product_id]": "1",

"order_products[1][product_id]": "2",

"factory_id": "1",

"order_products[2][size_id]": "2",

"order_products[2][product_id]": "3",

"order_products[1][size_id]": "1",

"order_products[1][quantity]": "10",

"order_products[2][quantity]": "10"],


["order_products[0][size_id]": "1",

"order_products[0][quantity]": "10",

"order_products[0][product_id]": "1",

"order_products[1][product_id]": "2",

"factory_id": "1",

"order_products[2][size_id]": "1",

"order_products[2][product_id]": "3",

"order_products[1][size_id]": "1",

"order_products[1][quantity]": "10",

"order_products[2][quantity]": "10"]]



Is it what you are looking for ?

2
10
Body quantity -  ["order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[0][size_id]": "2", "factory_id": "1"]
1
10
Body quantity -  ["order_products[0][quantity]": "10", "order_products[0][product_id]": "1", "order_products[0][size_id]": "1", "factory_id": "1"]
2
10
Body quantity -  ["order_products[0][size_id]": "1", "order_products[1][quantity]": "10", "factory_id": "1", "order_products[1][size_id]": "2", "order_products[0][quantity]": "10", "order_products[1][product_id]": "2", "order_products[0][product_id]": "1"]
1
10
Body quantity -  ["order_products[0][size_id]": "1", "order_products[1][quantity]": "10", "factory_id": "1", "order_products[1][size_id]": "1", "order_products[0][quantity]": "10", "order_products[1][product_id]": "2", "order_products[0][product_id]": "1"]
2
10
Body quantity -  ["order_products[2][size_id]": "2", "order_products[0][size_id]": "1", "order_products[1][quantity]": "10", "factory_id": "1", "order_products[2][quantity]": "10", "order_products[1][size_id]": "1", "order_products[0][quantity]": "10", "order_products[2][product_id]": "3", "order_products[1][product_id]": "2", "order_products[0][product_id]": "1"]
1
10
Body quantity -  ["order_products[2][size_id]": "1", "order_products[0][size_id]": "1", "order_products[1][quantity]": "10", "factory_id": "1", "order_products[2][quantity]": "10", "order_products[1][size_id]": "1", "order_products[0][quantity]": "10", "order_products[2][product_id]": "3", "order_products[1][product_id]": "2", "order_products[0][product_id]": "1"]


Here is what I have, when I run this func and for in loop

You can run my code in playground and see the result as well. I'm testing it in playgound before putting inside my app

What is not clear is why you loop for all (id, size) ; it should depend if the product needs it ? But I see nowhere defined which product have what quantity

First of all - many thanks for helping me!


Size id and quantity can change. In my sample I showed case, where sizes have different ids, but same quantity. There are three cases: same quantity - different ids, different quantity and different ids, no id, just quantity. All these cases belong to one product.

So, product with id - 1 can have: var quantity = ["1" : "10", "2": "10"] , same goes to product with id - 2 - var quantity = ["1" : "10", "2": "10"] , and for instance, product with id - 3 can be like var quantity = ["1" : "15", "2": "20"], last possible case is product with let's say id - 4, where it can have only quantity as "10" and that's all.

Maybe, it should be better to separate this loops?

As for final body - almost, it should look like this:

  • ["factory_id": "1",
  • "order_products[0][product_id]": "1"
  • "order_products[0][size_id]": "2",
  • "order_products[0][quantity]": "10",
  • "order_products[1][product_id]": "2",
  • "order_products[1][size_id]": "2",
  • "order_products[1][quantity]": "10",
  • "order_products[2][product_id]": "3",
  • "order_products[2][size_id]": "2",
  • "order_products[2][quantity]": "10"]

Of course, order of elements can be any. Your solutions is almost there. This is the body I have to send to my back-end. Also, I don't know, but is this a good practice to create such complicated body at the back-end side?

You structure is really complex


Probably you should create the body request:

- appending factory first

- then all the orders


In addition, you need to reset the createOrderBody dictionary in formBody


func formBody(products: String, factoryId: String, productId: String, size_id: String, quantity: String) -> [String: Any] {
    createOrderBody = [String: Any]()
    createOrderBody["factory_id"] = factoryId
    createOrderBody["order_products[\(products)][product_id]"] = productId
    createOrderBody["order_products[\(products)][size_id]"] = size_id
    createOrderBody["order_products[\(products)][quantity]"] = quantity
 
    return createOrderBody
}

With this modification, I get :


finalBody [[

"order_products[0][quantity]": "10",

"order_products[0][size_id]": "1",

"order_products[0][product_id]": "1",

"factory_id": "1"],


["order_products[0][quantity]": "10",

"order_products[0][size_id]": "2",

"order_products[0][product_id]": "1",

"factory_id": "1"],


["order_products[1][product_id]": "2",

"order_products[1][size_id]": "1",

"order_products[1][quantity]": "10",

"factory_id": "1"],


["order_products[1][product_id]": "2",

"order_products[1][size_id]": "2",

"order_products[1][quantity]": "10",

"factory_id": "1"],


["order_products[2][product_id]": "3",

"order_products[2][size_id]": "1",

"order_products[2][quantity]": "10",

"factory_id": "1"],


["order_products[2][product_id]": "3",

"order_products[2][size_id]": "2",

"order_products[2][quantity]": "10",

"factory_id": "1"]]

I see.
Ok, then let's forget about factory, we can append it later on. How should we append products with quantities? Maybe we should split this loop into parts. Like first create one product with quantites, then second, third and so on...?

So, product with id - 1 can have: var quantity = ["1" : "10", "2": "10"] , same goes to product with id - 2 - var quantity = ["1" : "10", "2": "10"] , and for instance, product with id - 3 can be like var quantity = ["1" : "15", "2": "20"], last possible case is product with let's say id - 4, where it can have only quantity as "10" and that's all.


Seems each product with id needs to hold its own `quantity` separately.


You can define a struct like this:

struct Product {
    let id: String
    let quantities: [(sizeId: String, quantity: Int)]?
    let noIdQuantity: Int?
    
    init(id: String, quantities: [(sizeId: String, quantity: Int)]) {
        self.id = id
        self.quantities = quantities
        self.noIdQuantity = nil
    }
    
    init(id: String, quantity: Int) {
        self.id = id
        self.quantities = nil
        self.noIdQuantity = quantity
    }
}


With the struct above, you just need only one input variable and one output variable:

// Define your input `product with id` as an Array of `Product`
let products = [
    Product(id: "1", quantities: [("1", 10), ("2", 10)]),
    Product(id: "2", quantities: [("1", 10), ("2", 10)]),
    Product(id: "3", quantities: [("1", 15), ("2", 20)]),
    Product(id: "4", quantity: 10),
]
// Output dictionary
var body = [String: Any]()


To make entries for a single Product into a Dictionary:

extension Product {
    func formBody(_ index: inout Int, into body: inout [String: Any]) {
        if let quantities = self.quantities {
            for (sizeId, quantity) in quantities {
                body["order_products[\(index)][product_id]"] = self.id
                body["order_products[\(index)][size_id]"] = sizeId
                body["order_products[\(index)][quantity]"] = quantity
                index += 1
            }
        }
        if let quantity = self.noIdQuantity {
            body["order_products[\(index)][product_id]"] = self.id
            body["order_products[\(index)][quantity]"] = quantity
            index += 1
        }
    }
}


And use them as follows:

var index = 0
body["factory_id"] = "1"
for product in products {
    product.formBody(&index, into: &body)
}
print("Body quantity - ", body)
body.sorted {$0.key < $1.key}.forEach{print("\($0.key)=\($0.value)")} //For showing readable result, not for Alammofire body


Result:

Body quantity - ["order_products[4][quantity]": 15,"order_products[5][product_id]": "3", "order_products[3][size_id]": "2", "order_products[5][size_id]": "2", "order_products[5][quantity]": 20, "order_products[0][product_id]": "1", "order_products[4][size_id]": "1", "order_products[2][size_id]": "1", "order_products[2][quantity]": 10, "order_products[3][product_id]": "2", "order_products[0][size_id]": "1", "order_products[1][quantity]": 10, "order_products[2][product_id]": "2", "order_products[3][quantity]": 10, "order_products[6][quantity]": 10, "order_products[1][size_id]": "2", "order_products[6][product_id]": "4", "order_products[0][quantity]": 10, "order_products[1][product_id]": "1", "order_products[4][product_id]": "3", "factory_id": "1"]

factory_id=1

order_products[0][product_id]=1

order_products[0][quantity]=10

order_products[0][size_id]=1

order_products[1][product_id]=1

order_products[1][quantity]=10

order_products[1][size_id]=2

order_products[2][product_id]=2

order_products[2][quantity]=10

order_products[2][size_id]=1

order_products[3][product_id]=2

order_products[3][quantity]=10

order_products[3][size_id]=2

order_products[4][product_id]=3

order_products[4][quantity]=15

order_products[4][size_id]=1

order_products[5][product_id]=3

order_products[5][quantity]=20

order_products[5][size_id]=2

order_products[6][product_id]=4

order_products[6][quantity]=10

Hi,
Yes, that is what I was looking for! This amazing, and wow, this turned out to be a really complicated task.
Thank you very much for your help! I see that I still have alot to study in programming and Swift 🙂


Once again - thank you!
Have a nice weekends and good luck!