-1

I am trying to compose a representative URLComponents() in the app I am designing.

Here is the code:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    var components = URLComponents()

    components.scheme = "http"
    components.host = "0.0.0.0"
    components.port = 9090
    let queryItemToken = URLQueryItem(name: "/predict?text", value: "what's your name?")
    components.queryItems = [queryItemToken]

    print(components.url as Any)
    }
}

Here is the output of the above snippet:

Optional(http://0.0.0.0:9090?/predict?text=what's%20your%20name?)

The above output doesn't work on the server because of the ? between the port and the query! How can I prevent URLComponents() from inserting this redundant ? between the port and the query!

The target output: Optional(http://0.0.0.0:9090/predict?text=what's%20your%20name?)

Cœur
  • 32,421
  • 21
  • 173
  • 232
mansanto
  • 330
  • 2
  • 14

2 Answers2

4

The /predict part is the path, not a query item. text is the actual query parameter.

You want:

var components = URLComponents()
components.scheme = "http"
components.host = "0.0.0.0"
components.port = 9090
components.path = "/predict"
let queryItemToken = URLQueryItem(name: "text", value: "what's your name?")
components.queryItems = [queryItemToken]
print(components.url!)
rmaddy
  • 298,130
  • 40
  • 468
  • 517
  • @maddy - you're so quick with these answer, small thing though doesn't the `print(components.url!)` force unwrap a nil? – Craig Jan 02 '19 at 22:44
  • The `!` force unwraps an optional, not a nil. If it was nil it would have crashed. It would be nil if your components didn't create a valid URL. It's just a `print` statement for debugging purposes so it doesn't matter if it crashes during development. But certainly do not leave it there. – rmaddy Jan 02 '19 at 22:57
  • I found the problem in my Playground I'd left off the leading `/` when setting the path… `components.path = "predict"` fails – Craig Jan 02 '19 at 23:01
  • Yes, it would. That's why I set the path to `"/predict"` and not `"predict"` in my answer. – rmaddy Jan 02 '19 at 23:03
-2

Thank you all for the response. I got away with all this by doing the following without the need to use URLComponents().

It turned out that sending some raw special characters in the query can be devastating to the request to the network.

And then, I use a dictionary to replace some special characters in the raw input before processing further, everything else works smooth. Thanks a lot for the attention.

So, assuming the user raw input is input:

import UIKit
import Foundation

// An example of a user input
var input = "what's your name?"

// ASCII Encoding Reference: important to allow primary communication with the server
var mods = ["'": "%27",
        "’": "%27",
        " ": "%20",
        "\"" : "%22",
        "<" : "%3C",
        ">" : "%3E"]

for (spChar, repl) in mods {
        input = input.replacingOccurrences(of: spChar, with: repl, options: .literal, range: nil)
    }

let query = "http://0.0.0.0:9090/predict?text=" + input

This is my third day with swift, I am sure there must be cleaner approaches to handle these nuances.

mansanto
  • 330
  • 2
  • 14
  • 1
    If you don't want to use `URLComponent` then please search how to do "URL-encoding" in Swift correctly, e.g. https://stackoverflow.com/a/39767927/669586 – Sulthan Jan 03 '19 at 14:16
  • This encoding is wrong. There are more special characters than these. Most importantly `%`. Do not try to hand-encode URLs. It's extremely complicated. Use URLComponents, which does it correctly for you. – Rob Napier Jan 03 '19 at 15:53
  • *"I am sure there must be cleaner approaches to handle these nuances"* - yes, use `URLComponents`. – rmaddy Jan 03 '19 at 16:26
  • I tried to use the URLComponents implementing rmaddy's correct answer to my posted issue and it didn't resolve these special characters related issues. For example, URLComponents never replaced the apostrophe in a user input of "what's your name?" with the %27 and that made all the difference in my specific case. I looked around and I couldn't find any method in the URLComponents class which would solve this specific problem and shields me from hand-coding. – mansanto Jan 04 '19 at 05:21
  • @mansanto The `'` doesn't need to be escaped. It's not a special URL character. That's why URLComponents didn't escape it. And your question shows that your desired output doesn't escape the `'`. – rmaddy Jan 04 '19 at 05:47
  • when ' is not replaced with its ascii representation, the network request fails, when it is replaced with %27, the network request succeeds. – mansanto Jan 04 '19 at 06:05