> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/resources/textbook/networking-ii/urlsession.md).

# URLSession

In the previous sections, we used Alamofire to send network requests. Although Alamofire is very elegant and simple to use, there are times when we want to use native Swift to send network requests. We can do this with **URLSession**.

### GET Requests

Let’s take a look at the Alamofire version from the previous section:

```swift
// 1. Create the function
func fetchRoster(completion: @escaping ([Member]) -> Void) {
    // 2. Specify the endpoint
    let endpoint = "<Enter URL String Here>"
    
    // 3. Create a decoder
    let decoder = JSONDecoder()
    // decoder.dateDecodingStrategy = .iso8601 // Only if needed
    // decoder.keyDecodingStrategy = .convertFromSnakeCase // Only if needed
    
    // 4. Create the request
    AF.request(endpoint, method: .get)
        .validate()
        .responseDecodable(of: [Member].self, decoder: decoder) { response in
	    // 5. Handle the response
            switch response.result {
            case .success(let members):
                print("Successfully fetched \(members.count) members")
                completion(members)
            case .failure(let error):
                print("Error in NetworkManager.fetchRoster: \(error)")
            }
        }
}
```

We can do the same exact thing using URLSession **(only steps after Step 3 are different):**

```swift
// 1. Create the function
func fetchRoster(completion: @escaping ([Member]) -> Void) {
    // 2. Specify the endpoint
    let endpoint = "<Enter URL String Here>"
    
    // 3. Create a decoder
    let decoder = JSONDecoder()
    // decoder.dateDecodingStrategy = .iso8601 // Only if needed
    // decoder.keyDecodingStrategy = .convertFromSnakeCase // Only if needed

    // 4. Create a URLRequest
    var urlRequest = URLRequest(url: URL(string: endpoint)!)
    urlRequest.httpMethod = "GET"
    
    // 5. Create and resume the task
    URLSession.shared.dataTask(with: urlRequest) { data, response, error in
        // 6. Handle the response (you can also do something with `response`)
        guard error == nil, let data else {
            print("Error in NetworkManager.fetchRoster: \(error)")
            return
        }

        if let members = try? decoder.decode([Member].self, from: data) {
            completion(members)
        }
    }
    .resume()
}
```

### POST Requests

Let’s take a look at a POST request using Alamofire:

```swift
// 1. Create the function
func addToRoster(member: Member, completion: @escaping (Member) -> Void) {
    // 2. Specify the endpoint
    let endpoint = "<Enter URL String Here>"

    // 3. Define the request body
    let parameters: Parameters = [
	"name": member.name,
	"subteam": member.subteam,
	"position": member.position
    ]
    
    // 4. Create a decoder
    let decoder = JSONDecoder()
    // decoder.dateDecodingStrategy = .iso8601 // Only if needed
    // decoder.keyDecodingStrategy = .convertFromSnakeCase // Only if needed
    
    // 5. Create the request
    AF.request(endpoint, method: .post, parameters: parameters, encoding: JSONEncoding.default)
        .validate()
        .responseDecodable(of: Member.self, decoder: decoder) { response in
	    // 5. Handle the response
            switch response.result {
            case .success(let member):
                print("Successfully added member \(member.name)")
                completion(member)
            case .failure(let error):
                print("Error in NetworkManager.addToRoster: \(error.localizedDescription)")
            }
        }
}
```

If we were to use URLSession, we need to:

* Change the `httpMethod` property of the `URLRequest` to `"POST"`.
* Call the `setValue` function with `("application/json", forHTTPHeaderField: "Content-Type")`.
* Set the `httpBody` property of the `URLRequest`.
  * The code below uses `JSONSerialization` to serialize the dictionary `parameters` to JSON and use it as the request body.
  * Alternatively, we can also use a `JSONEncoder` to encode our object into JSON, but it won’t be shown here.

```swift
// 1. Create the function
func addToRoster(member: Member, completion: @escaping (Member) -> Void) {
    // 2. Specify the endpoint
    let endpoint = "<Enter URL String Here>"

    // 3. Define the request body
    let parameters = [
        "name": member.name,
        "subteam": member.subteam,
        "position": member.position
    ]
    guard let httpBody = try? JSONSerialization.data(
        withJSONObject: parameters,
        options: []
    ) else { return }

    // 4. Create a decoder
    let decoder = JSONDecoder()
    // decoder.dateDecodingStrategy = .iso8601 // Only if needed
    // decoder.keyDecodingStrategy = .convertFromSnakeCase // Only if needed

    // 5. Create a URLRequest
    var urlRequest = URLRequest(url: URL(string: endpoint)!)
    urlRequest.httpMethod = "POST"
    urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.httpBody = httpBody

    // 6. Create and resume the task
    URLSession.shared.dataTask(with: urlRequest) { data, response, error in
        // 7. Handle the response (you can also do something with `response`)
        guard error == nil, let data else {
            print("Error in NetworkManager.addToRoster: \\(error)")
            return
        }

        if let member = try? decoder.decode(Member.self, from: data) {
            completion(member)
        }
    }
    .resume()
}
```

{% hint style="info" %}
**Note that we do not have to create the decoder inside of the function call. We can create a&#x20;**<mark style="color:red;">**`JSONDecoder`**</mark>**&#x20;object and store it as a property in our&#x20;**<mark style="color:red;">**`NetworkManager`**</mark>**&#x20;class to be used for all functions. The same can be applied to the `endpoint` variable containing a String value of our endpoint.**
{% endhint %}
