Working with API in Swift: REST, GraphQL, gRPC – What to Choose in 2025?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

API in Swift: From Theory to Real Requests

\n\n

Every iOS developer sooner or later faces the need for an application to communicate with a server. Whether it's loading a news feed, sending form data, or real-time streaming — you can't do without an API (Application Programming Interface). But which protocol to choose? Classic REST, flexible GraphQL, or ultra-fast gRPC?

\n\n

In this article, we won't just list the pros and cons. We'll break down working with API in Swift using real examples, show code, and give practical advice. You'll learn how to properly structure the network layer, which libraries to use, and when each approach becomes the best choice.

\n\n

If you write in Swift and want your application to communicate with the backend quickly, reliably, and elegantly — this article is for you. Let's go!

\n\n

REST API in Swift: A Classic That Never Gets Old

\n\n

REST (Representational State Transfer) is an architectural style that uses HTTP methods (GET, POST, PUT, DELETE) to work with resources. Most public APIs (GitHub, Twitter, Stripe) are built on REST. For a Swift developer, this means you'll be working with JSON, URLSession, or Alamofire.

\n\n

Basic GET Request with URLSession

\n\n

Let's start with the simplest — fetching data. Imagine we need to load a list of users from JSONPlaceholder:

\n\n
import Foundation\n\nstruct User: Codable {\n    let id: Int\n    let name: String\n    let email: String\n}\n\nfunc fetchUsers() async throws -> [User] {\n    let url = URL(string: "https://jsonplaceholder.typicode.com/users")!\n    let (data, response) = try await URLSession.shared.data(from: url)\n    \n    guard let httpResponse = response as? HTTPURLResponse,\n          (200...299).contains(httpResponse.statusCode) else {\n        throw URLError(.badServerResponse)\n    }\n    \n    return try JSONDecoder().decode([User].self, from: data)\n}\n\nTask {\n    do {\n        let users = try await fetchUsers()\n        print("Loaded \\(users.count) users")\n    } catch {\n        print("Error: \\(error.localizedDescription)")\n    }\n}
\n\n

Notice the use of async/await — this is the modern way to work with asynchronous code in Swift. The code has become readable and concise, without closures and callbacks.

\n\n

POST Request with Alamofire

\n\n

Alamofire is the most popular library for networking in Swift. It simplifies error handling, parameter encoding, and file uploads. Here's an example of sending data:

\n\n
import Alamofire\n\nstruct NewUser: Encodable {\n    let name: String\n    let email: String\n}\n\nAF.request("https://jsonplaceholder.typicode.com/users",\n           method: .post,\n           parameters: NewUser(name: "Ivan", email: "ivan@example.com"),\n           encoder: JSONParameterEncoder.default)\n    .validate()\n    .responseDecodable(of: User.self) { response in\n        switch response.result {\n        case .success(let user):\n            print("Created user with id: \\(user.id)")\n        case .failure(let error):\n            print("Error: \\(error.localizedDescription)")\n        }\n    }
\n\n

Tip: Use .validate() — it will automatically check the status code and convert HTTP errors into Alamofire errors. Your code will become cleaner, and debugging easier.

\n\n

When is REST the Best Choice?

\n
    \n
  • You have a simple CRUD application (notes, task list).
  • \n
  • The API provides fixed endpoints.
  • \n
  • You don't need complex data nesting.
  • \n
\n\n

GraphQL in Swift: Query Flexibility

\n\n

GraphQL is a query language that allows the client to request exactly the data it needs. No over-fetching (extra fields) or under-fetching (multiple requests needed). For Swift, there is an excellent library Apollo iOS

Blogs

Book Recommendations