Swift
URL construction
query parameters
multiple values
programming tutorial

How can I build a URL with query parameters containing multiple values for the same key in Swift?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Some APIs accept repeated query keys such as tag=swift&tag=ios instead of a single comma-separated value. In Swift, the safest way to build that kind of URL is with URLComponents, because it preserves repeated keys and handles percent encoding correctly.

Use Repeated URLQueryItem Values

URLComponents stores query parameters as an array of URLQueryItem, not as a dictionary. That matters because dictionaries cannot represent repeated keys without losing information.

Here is the basic pattern:

swift
1import Foundation
2
3var components = URLComponents(string: "https://api.example.com/search")!
4components.queryItems = [
5    URLQueryItem(name: "tag", value: "swift"),
6    URLQueryItem(name: "tag", value: "ios"),
7    URLQueryItem(name: "sort", value: "recent")
8]
9
10print(components.url!.absoluteString)

The resulting URL is:

text
https://api.example.com/search?tag=swift&tag=ios&sort=recent

Because each repeated value is its own URLQueryItem, the final query string keeps both tag entries in order.

Build Repeated Parameters from Arrays

In real code, repeated query keys often come from an array such as selected filters or category ids. A helper function makes the construction predictable:

swift
1import Foundation
2
3func makeURL(baseURL: String, tags: [String], sort: String) -> URL? {
4    var components = URLComponents(string: baseURL)
5
6    let tagItems = tags.map { URLQueryItem(name: "tag", value: $0) }
7    let sortItem = URLQueryItem(name: "sort", value: sort)
8
9    components?.queryItems = tagItems + [sortItem]
10    return components?.url
11}
12
13let url = makeURL(
14    baseURL: "https://api.example.com/search",
15    tags: ["swift", "ios", "networking"],
16    sort: "recent"
17)
18
19print(url?.absoluteString ?? "invalid URL")

This keeps the repeated-key behavior explicit and avoids manual string concatenation.

Do Not Use a Dictionary for Repeated Keys

A common first attempt is something like this:

swift
let params = ["tag": "swift", "tag": "ios"]

That does not work the way people expect, because dictionary keys must be unique. One of the values wins and the other is lost. If the API requires repeated keys, use an ordered array of URLQueryItem instead.

Match the Server’s Expected Format

Not every backend expects the same syntax. Many APIs accept repeated keys:

text
tag=swift&tag=ios

Others want bracketed names:

text
tag[]=swift&tag[]=ios

If the server expects the bracketed form, keep the repeated structure but change the item name:

swift
1components.queryItems = [
2    URLQueryItem(name: "tag[]", value: "swift"),
3    URLQueryItem(name: "tag[]", value: "ios")
4]

The important point is that the repetition happens through multiple query items, not through a single combined string unless the API documentation explicitly says otherwise.

Let Foundation Handle Encoding

URLComponents is also valuable because it encodes reserved characters correctly. If a filter value contains spaces, punctuation, or symbols, Foundation handles the escaping for you:

swift
1var components = URLComponents(string: "https://api.example.com/search")!
2components.queryItems = [
3    URLQueryItem(name: "tag", value: "machine learning"),
4    URLQueryItem(name: "tag", value: "c++")
5]
6
7print(components.url!.absoluteString)

Manual string building often gets this wrong, especially once spaces, ampersands, or plus signs appear in the values.

Common Pitfalls

The biggest pitfall is using a dictionary to represent query parameters when the API allows repeated keys. Dictionaries are the wrong data structure for that job.

Another common mistake is building the query string manually with string interpolation. That works for simple cases, then breaks as soon as a value needs percent encoding.

It is also easy to assume every backend parses arrays the same way. Some expect repeated keys, some expect bracketed names, and others expect a comma-separated string. Check the API contract before choosing the format.

Finally, remember that components.url is optional. If the base URL is invalid, the final URL will be nil, so treat construction as a potentially failing step.

Summary

  • Use URLComponents with multiple URLQueryItem entries to represent repeated query keys.
  • Do not use a dictionary when duplicate keys must be preserved.
  • Build repeated items from arrays to keep the code clear and maintainable.
  • Match the exact query syntax expected by the server, whether repeated keys or bracketed names.
  • Let Foundation handle percent encoding instead of building query strings by hand.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions