Swift
sendSynchronousRequest
response statusCode
HTTP request
programming tutorial

How To Check Response.statusCode in sendSynchronousRequest on Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you are using the old synchronous request API in Swift, the statusCode is available on the returned response object after you cast it to HTTPURLResponse. The broader point, though, is that synchronous requests are legacy behavior and should be reserved for controlled contexts such as command-line tools or background-only code, not UI work.

Cast the Response to HTTPURLResponse

The HTTP status code is not available on the generic URLResponse type. You need to cast it to HTTPURLResponse before reading statusCode.

A typical Foundation example looks like this:

swift
1import Foundation
2
3let url = URL(string: "https://httpbin.org/status/200")!
4let request = URLRequest(url: url)
5
6var response: URLResponse?
7var error: NSError?
8
9let data = NSURLConnection.sendSynchronousRequest(
10    request,
11    returning: &response,
12    error: &error
13)
14
15if let httpResponse = response as? HTTPURLResponse {
16    print("Status code: \(httpResponse.statusCode)")
17}
18
19if let error = error {
20    print("Request failed: \(error.localizedDescription)")
21}
22
23print("Bytes received: \(data?.count ?? 0)")

The important line is the cast:

swift
if let httpResponse = response as? HTTPURLResponse

Without that cast, Swift only sees a generic response object and statusCode is not available.

Understand the Difference Between Network Failure and HTTP Failure

An HTTP 404 or 500 is still a valid HTTP response, so error may be nil even when the request failed from the application's perspective. That means you need to check both the transport error and the status code.

A practical pattern is:

swift
1if let error = error {
2    print("Transport error: \(error)")
3} else if let httpResponse = response as? HTTPURLResponse {
4    switch httpResponse.statusCode {
5    case 200...299:
6        print("Success")
7    case 400...499:
8        print("Client error")
9    case 500...599:
10        print("Server error")
11    default:
12        print("Other status: \(httpResponse.statusCode)")
13    }
14}

This keeps network-layer problems separate from application-layer HTTP results.

Why This API Is Usually the Wrong Choice Today

NSURLConnection.sendSynchronousRequest blocks the current thread until the request finishes. On the main thread, that can freeze a macOS or iOS interface. That is why modern Swift networking generally uses URLSession with async callbacks or async-await.

The modern equivalent is much cleaner:

swift
1import Foundation
2
3let url = URL(string: "https://httpbin.org/status/200")!
4
5URLSession.shared.dataTask(with: url) { data, response, error in
6    if let error = error {
7        print("Transport error: \(error)")
8        return
9    }
10
11    if let httpResponse = response as? HTTPURLResponse {
12        print("Status code: \(httpResponse.statusCode)")
13    }
14}.resume()

So if you are only asking how to read the status code, the answer is the cast. If you are designing new code, the real answer is to move away from synchronous requests entirely.

A Small Helper Function

If you are maintaining legacy code and want the status code logic in one place, wrap it in a helper.

swift
1import Foundation
2
3func fetchSynchronously(_ request: URLRequest) -> Int? {
4    var response: URLResponse?
5    var error: NSError?
6
7    _ = NSURLConnection.sendSynchronousRequest(
8        request,
9        returning: &response,
10        error: &error
11    )
12
13    if error != nil {
14        return nil
15    }
16
17    return (response as? HTTPURLResponse)?.statusCode
18}

That keeps the cast and error handling together and makes the rest of the code clearer.

Common Pitfalls

  • Trying to read statusCode from URLResponse directly does not work. You must cast to HTTPURLResponse.
  • Assuming error == nil means the request succeeded is incorrect because HTTP 404 and 500 still return valid responses.
  • Running synchronous requests on the main thread can freeze the user interface.
  • Ignoring the response body makes debugging harder when the server returns useful error details along with the status code.
  • Writing new networking code around sendSynchronousRequest is a maintenance problem because the API is legacy and modern Swift uses URLSession instead.

Summary

  • Cast the returned response to HTTPURLResponse to access statusCode.
  • Check both the transport error and the HTTP status code because they represent different failure modes.
  • Use synchronous requests only in limited non-UI scenarios.
  • Prefer URLSession for modern Swift code.
  • If you must keep the legacy API, wrap the cast and status handling in a small helper function.

Course illustration
Course illustration

All Rights Reserved.