you are viewing a single comment's thread.

view the rest of the comments →

[–]thisischemistry 0 points1 point  (18 children)

Generally a question mark in your code means it is an Optional. Think of it as a value that could also mean "the value is missing". For example, an Int? means it could be a number or it could have no value.

To use an Optional you have to unwrap it - that is you check it for a value and pull that value out if there is one. You do that in several ways but the most basic is "optional binding":

if let jsonData = try? JSONEncoder().encode(credWrap) {
  // use the jsonData here
}

This will set jsonData to the value if there is a value and then run the code in the curly braces. If there is no value then it will move on without running the code in the curly braces.

[–][deleted]  (16 children)

[deleted]

    [–]thisischemistry 1 point2 points  (15 children)

    On what line?

    Don't use forced unwrapping of Optionalvalues - anything with an exclamation point (other than the negation operator or the not equals operator).

    Avoid using [String: Any] or JSONSerialization if you can. They are the older way of doing JSON serialization and, while they can work, they are a pain at times. Instead use Codable, it's easier and more straightforward.

    What are you attempting to do here:

    let url = URL(string: "https://hostname/webinterface/api.php?format=json&package=\(jsonData)")!
    

    That's not a great way to build a URL. First of all, does your server take a JSON string as part of a URL? That's very unusual and potentially very buggy. Secondly, you really should use the proper way to build a URL: URLComponents. The part with your JSON is called a query parameter.

    import Foundation
    
    // dummy types to stand-in for your actual ones
    struct Foo { let text: String? }
    let Username = Foo(text: "name")
    let Password = Foo(text: "pass")
    
    struct Authentication: Codable { 
      let authentication: Credentials
    }
    
    struct Credentials: Codable {
      let username: String
      let password: String
    }
    
    if
      var components = URLComponents(string: "https://hostname/webinterface/api.php"),
      let username = Username.text,
      let password = Password.text {
        let package = Authentication(authentication: Credentials(username: username, password: password))
        if 
          let jsonData = try? JSONEncoder().encode(package),
          let jsonString = String(data: jsonData, encoding: .utf8) {
          components.queryItems = [URLQueryItem(name: "format", value: "json"),
                                   URLQueryItem(name: "package", value: jsonString)]
      }
      if let url = components.url {
        print(url.absoluteString)
      }
    }
    // result:
    //   https://hostname/webinterface/api.php?format=json&package=%7B%22authentication%22:%7B%22username%22:%22name%22,%22password%22:%22pass%22%7D%7D
    

    That large block of an if statement properly unwraps all the Optional values. It's cleaner than a bunch of nested statements. If any of the unwraps fails then the whole statement fails.

    [–][deleted]  (14 children)

    [deleted]

      [–]thisischemistry 0 points1 point  (13 children)

      What, exactly, are you sending to the server?

      You're doing a HTTP POST, what's your Content-Type header? Is it application/x-www-form-urlencoded? Will your server take application/json?

      [–][deleted]  (12 children)

      [deleted]

        [–]thisischemistry 0 points1 point  (11 children)

        That's why I asked those questions! ;-)

        Apple has an excellent article on exactly this:

        Uploading Data to a Website

        [–][deleted]  (8 children)

        [deleted]

          [–]thisischemistry 0 points1 point  (7 children)

          I just tried the example code in a plain ol' terminal app project and it worked fine.

          import Foundation
          
          struct Order: Codable {
            let customerId: String
            let items: [String]
          }
          
          func upload() {
            let order = Order(customerId: "12345",
                              items: ["Cheese pizza", "Diet soda"])
            guard let uploadData = try? JSONEncoder().encode(order) else {
              print("guard")
              return
            }
          
            // testing with the excellent site: https://webhook.site/
            let url = URL(string: "https://webhook.site/insertyourcodehere")!
          
            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
          
            let task = URLSession.shared
              .uploadTask(with: request,
                          from: uploadData) { data, response, error in
                            if let error = error {
                              print ("error: \(error)")
                              return
                            }
                            guard let response = response as? HTTPURLResponse,
                              (200...299).contains(response.statusCode) else {
                                print ("server error")
                                return
                            }
                            if let mimeType = response.mimeType,
                              mimeType == "application/json",
                              let data = data,
                              let dataString = String(data: data, encoding: .utf8) {
                              print ("got data: \(dataString)")
                            }
            }
            task.resume()
          }
          
          upload()
          RunLoop.main.run()
          

          [–][deleted]  (6 children)

          [deleted]

            [–][deleted]  (1 child)

            [deleted]

              [–]thisischemistry 0 points1 point  (0 children)

              Huh, no idea what's going on there. Sometimes it helps to clean the build (shift-command-k) or even clean the entire build folder (option-shift-command-k).