Swift
GET request
HTTP parameters
iOS development
networking

Swift GET request with parameters

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In Swift, a GET request with parameters is usually built by adding query items to the URL rather than by placing data in the HTTP body. The safest way to do that is with URLComponents, because it handles percent-encoding correctly. Once the URL is built, URLSession performs the request in the normal way.

Build the URL with URLComponents

Start by creating the base URL and attaching query items:

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

This is better than manual string concatenation because special characters in parameter values are encoded correctly.

Execute the GET Request with URLSession

With async and await, the request code is compact and readable:

swift
1import Foundation
2
3func fetchSearchResults() async throws -> Data {
4    var components = URLComponents(string: "https://api.example.com/search")!
5    components.queryItems = [
6        URLQueryItem(name: "q", value: "swift networking"),
7        URLQueryItem(name: "page", value: "1")
8    ]
9
10    var request = URLRequest(url: components.url!)
11    request.httpMethod = "GET"
12
13    let (data, response) = try await URLSession.shared.data(for: request)
14
15    guard let httpResponse = response as? HTTPURLResponse,
16          200...299 ~= httpResponse.statusCode else {
17        throw URLError(.badServerResponse)
18    }
19
20    return data
21}

The query parameters are part of the URL, while the request method stays GET.

Decode JSON into a Swift Type

In real apps, you usually decode the response rather than using raw Data.

swift
1import Foundation
2
3struct SearchResponse: Decodable {
4    let results: [String]
5}
6
7func fetchDecodedResults() async throws -> SearchResponse {
8    let data = try await fetchSearchResults()
9    return try JSONDecoder().decode(SearchResponse.self, from: data)
10}

This keeps the networking layer typed and easier to maintain.

Completion-Handler Version

If you are working in older code that does not use async and await yet, the same request can be made with dataTask:

swift
1import Foundation
2
3var components = URLComponents(string: "https://api.example.com/search")!
4components.queryItems = [
5    URLQueryItem(name: "q", value: "swift networking")
6]
7
8let task = URLSession.shared.dataTask(with: components.url!) { data, response, error in
9    if let error = error {
10        print("Request failed:", error)
11        return
12    }
13
14    guard let httpResponse = response as? HTTPURLResponse,
15          200...299 ~= httpResponse.statusCode,
16          let data = data else {
17        print("Bad response")
18        return
19    }
20
21    print("Received bytes:", data.count)
22}
23
24task.resume()

If you need to update the UI afterward, hop back to the main thread.

Why GET Parameters Belong in the URL

By convention and in practice, GET requests carry their parameters in the query string. Servers, caches, and proxies expect GET requests to be safe and URL-addressable. If the data is large, sensitive, or conceptually a request body, a POST request is usually the better fit.

That distinction also helps prevent a common bug: trying to attach httpBody to a GET request and expecting every server or middleware layer to treat it consistently.

Common Pitfalls

One common mistake is building the URL by hand with string concatenation. That often breaks when values contain spaces, slashes, or other characters that need encoding.

Another mistake is sending GET parameters in httpBody instead of using query items. Even if some server accepts it, it is not the normal or most interoperable approach.

Developers also sometimes ignore the HTTP status code and decode whatever came back. Always validate the response before assuming the data matches your model.

Finally, remember that URLSession callbacks do not update the UI on the main thread automatically. If the response changes visible state, switch back to the main actor or main queue.

Summary

  • Build GET parameters with URLComponents and URLQueryItem.
  • Use URLSession to perform the request after the URL is assembled.
  • Put GET parameters in the query string, not the request body.
  • Check HTTP status codes before decoding the response.
  • Prefer typed decoding with Decodable for maintainable networking code.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

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

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.