24. Mar 2023iOS

Exploring our iOS toolbox - Handling network requests in Swift

While Swift provides built-in networking capabilities, there are some disadvantages to using them, such as lack of standardisation, limited flexibility and challenges in maintaining and updating the codebase over time, especially as the number of endpoints grows. So, is there a more efficient way to accomplish this task?

Marek VricaniOS Developer

Well, great news! You can handle network requests more conveniently by using our GoodNetworking swift package. Let’s begin, shall we?

Preparing API & Endpoints

In this example, we will retrieve Star Wars heroes using the free Star Wars API.

To begin, we must first define the base URL for the ApiServer that conforms to the type String. We will also need to define an endpoint that conforms to the GREndpointManager protocol.

This endpoint will specify the path, method, parameters, headers, encoding, and URL for your network request.

You can define multiple endpoints for different network requests within your application.

import GoodNetworking
import Combine
import Alamofire

// define the base url of the api server
enum ApiServer: String {

    case base = "<https://swapi.dev/api/>"

}

// define Endpoint for fetching the StarWars heroes
// later on you can add edpoints for StarWars Planets or Starships
enum Endpoint: GREndpointManager {

case hero(id: Int)

    var path: String {
        switch self {
        case .hero(let id):
            return "people/\\(id)"
        }
    }

    var method: HTTPMethod { .get }

    var parameters: EndpointParameters? { nil }

    var headers: HTTPHeaders? {nil}

    var encoding: ParameterEncoding { JSONEncoding.default }

    func asURL(baseURL: String) throws -> URL {
        var url = try baseURL.asURL()
        url.appendPathComponent(path)
        return url
    }

}

Prepare API response

Next, we have to specify the expected response from the API. According the StarWars API, we expect a response with the name attribute of type String. We can define a struct with this attribute as follows:

// define the request response
struct HeroResponse: Decodable {
    
    let name: String
    
}

Now we have almost everything ready, we can setup our GRSession to make requests.

Making a network request

Once we have endpoint defined, we can create an instance of the GRSession.

**GRSession**is based on Alamofire Session class and ****manages network requests in client apps within its URLSession.

It takes two generic parameters:

  • (one conforming to GREndpointManager) - the Endpoint we defined earlier
  • (one conforming to RawRepresentable with RawValue of String) - our ApiServer

Here's an example of how you can use the GRSession class to make a network request:

// Create a GRSession object
let session: GRSession<Endpoint, ApiServer> = GRSession(
		baseURL: ApiServer.base
		configuration: .default
)

// fetch a hero with specified ID
func fetchHero(heroId: Int) -> AnyPublisher<HeroResponse, Never> {
		return session.request(endpoint: .hero(id: heroId))
		    .goodify()
				.replaceError(with: HeroResponse(name: "unknown"))
        .eraseToAnyPublisher()
}

The result of **fetchHero** function is a publisher so you can continue chaining Combine functions.

To show fetched StarWars hero’s name inside a label, simply call the function and use Combine’s sink or assign methods to achieve this goal.

// define heroLabel to show hero Name
let heroLabel = UILbel()

// define subscriber
var cancellable: AnyCancellable?

// subcribe to result of network request
cancellable = fetchHero(heroId: Int.random(1...66))
		.map { response in response.name }
		.removeDuplicates()
		.assing(to: \\.text, on: heroLabel, ownership: .weak)

Congrats!

You have gone through the process of making Network Request using GoodNetworking package.

Now you may be wondering how it works under the hood inside the app. Luckily, the package comes with a sample that you can explore to gain a deeper understanding of its functionality.

If you found this package useful, be sure to check out our other packages. Who knows, you might just find another gem that can help take your app to the next level!

Interested in what our entire solution stack looks like?

iOS

Our iOS tech stack for mobile app development

Sebastian Mráz13 Dec 2022
Marek VricaniOS Developer