> For the complete documentation index, see [llms.txt](https://prodigi.gitbook.io/bootcamp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://prodigi.gitbook.io/bootcamp/lesson-4-swift.md).

# Lesson 4 - Swift

## MVC (Model, View, Controller)

The **Model-View-Controller (MVC)** is an architectural pattern that separates an application into three main logical components: the model, the view, and the controller.

Each of these components are built to handle specific development aspects of an application. MVC is one of the most frequently used industry-standard web development framework to create scalable and extensible projects.

![](https://1164890588-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LFyi9t10d5wUEuocDHH%2F-LFyiKLmJ4Tnx6SFlTeb%2F-LFyiO7QlzppSH_5E5ou%2FMVC-grpah.png?generation=1530060707258057\&alt=media)

### Models

The objects that will be used to transport data.

### Views

Responsible to handle all UI interactions.

### Controllers

Responsible to handle all business code.

You can use the [MVC Base project](https://github.com/ProDigi-Developement/bootcamp/tree/mvc/base) as reference for your personal project.

## Calling a RESTful API

As a reference you can check the [Sample App code](https://github.com/ProDigi-Developement/bootcamp/tree/oop/swift-sample-app).

* Structuring calls
  * Create a simple and exclusive method to call the backend. On our example the function *fetch*
  * ```swift
    private func fetch(url: URLRequest, onSuccessScenario onSuccess: @escaping FetchSuccessScenario, onFailScenario onFail: @escaping FetchFailScenario) {
    ```

    The fetch method receives as parameters an URL variable of the type URLRequest and two callbacks to be able to return values on success and fail scenarios.
* Call backend
  * Implement the fetch method body code. On our example the code is
  * ```swift
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
        if let errorUnwrapped = error {
            onFail(errorUnwrapped.localizedDescription)
        } else {
            guard let httpResponse = response as? HTTPURLResponse else {
                onFail("Failed to parse HTTPURLResponse object")
                return
            }

            guard httpResponse.statusCode == 200 else {
                onFail("Failed to receive status code 200. Received: \(httpResponse.statusCode)")
                return
            }

            if let dataUnwrapped = data {
                onSuccess(dataUnwrapped)
            } else {
                onFail("No data from response.")
            }
        }
    })

    task.resume()
    ```

    The fetch body method is a generic code to handle any call and delivery the data from the response object. We have to create a DataTask object using the Session object and also we have to implement the **completitionHandler**, because only on this way we can handle properly the response from backend.
* Testing Class

  * Let's test the fetch method using the <https://randomuser.me/api>

  ```swift
  public func fetchUsers() {
      if let url = URL(string: "https://randomuser.me/api?results=20") {
          self.userList = [User]()

          let requestUrl = URLRequest(url: url)
          requestUrl.httpMethod = "GET"

          self.fetch(url: requestUrl, onSuccessScenario: onFetchUserSuccess, onFailScenario: onFetchUserFail)
      } else {
          // Call the delegate to notify the view of fail on fetch
          self.delegate?.fetchUsersFailed(errorMessage: "Not possible to create the URL object")
      }
  }

  // MARK: Fetch Users callbacks
  private func onFetchUserSuccess(data: Data) {
      do {
          // Convert the data object to users
          let userList = try self.convertToUsers(withData: data)

          // Fill the Controller user list
          self.userList = userList

          // Call the delegate to notify the view of success fetch
          self.delegate?.fetchedAllUsers()
      } catch {
          // Call the delegate to notify the view of fail on fetch
          self.delegate?.fetchUsersFailed(errorMessage: "Not possible to convert the JSON to User objects")
      }
  }

  private func onFetchUserFail(error: String) {
      // Call the delegate to notify the view of fail on fetch
      self.delegate?.fetchUsersFailed(errorMessage: error)
  }
  ```
