6

So I've been working on this tutorial by Gary Tokman to build a restaurant viewing app and it's great. From the beginning to the end, everything works properly and well.

The aim is to change or add a parameters and include either 'term' or 'categories'. This will then now change the search to a specific business than just restaurants.

This is where I'm stuck I cannot seem to find the proper syntax to execute this parameter.

This is Business Endpoint the documentation: https://www.yelp.com/developers/documentation/v3/business_search

These are the code for the swift file

Network Service File

import Foundation
import Moya

enum YelpService {
enum BusinessesProvider: TargetType {
    case search(lat: Double, long: Double)
    case details(id: String)

    var baseURL: URL {
        return URL(string: "https://api.yelp.com/v3/businesses")!
    }

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

    var method: Moya.Method {
        return .get
    }

    var sampleData: Data {
        return Data()
    }

    var task: Task {
        switch self {
        case let .search(lat, long):
            return .requestParameters(
                parameters: [ "latitude": lat, "longitude": long, "limit": 30], encoding: URLEncoding.queryString)
        case .details:
            return .requestPlain
        }
    }

    var headers: [String : String]? {
        return ["Authorization": "Bearer \(apiKey)"]
    }

}

AppDelegate File

import UIKit
import Moya
import CoreLocation

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

    let window = UIWindow()
    let locationService = LocationService()
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let service = MoyaProvider<YelpService.BusinessesProvider>()
    let jsonDecoder = JSONDecoder()
    var navigationController: UINavigationController?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
        [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase

        locationService.didChangeStatus = { [weak self] success in
            if success {
                self?.locationService.getLocation()
            }
        }

        locationService.newLocation = { [weak self] result in
            switch result {
            case .success(let location):
                self?.loadBusinesses(with: location.coordinate)
            case .failure(let error):
                assertionFailure("Error getting the users location \(error)")
            }
        }

        switch locationService.status {
        case .notDetermined, .denied, .restricted:
            let locationViewController = storyboard.instantiateViewController(withIdentifier:
                "LocationViewController")
                as? LocationViewController
            locationViewController?.delegate = self
            window.rootViewController = locationViewController
        default:
            let nav = storyboard
                .instantiateViewController(withIdentifier: "StoreNavigationController") as? UINavigationController
            self.navigationController = nav
            window.rootViewController = nav
            locationService.getLocation()
            (nav?.topViewController as? StoreTableViewController)?.delegate = self
        }
        window.makeKeyAndVisible()

        return true
    }

    private func loadDetails(for viewController: UIViewController, withId id: String) {
        service.request(.details(id: id)) { [weak self] (result) in
            switch result {
            case .success(let response):
                guard let strongSelf = self else { return }
                if let details = try? strongSelf.jsonDecoder.decode(Details.self, from: response.data) {
                    let detailsViewModel = DetailsViewModel(details: details)
                    (viewController as? DetailsStoreViewController)?.viewModel = detailsViewModel
                }
            case .failure(let error):
                print("Failed to get details \(error)")
            }
        }
    }

    private func loadBusinesses(with coordinate: CLLocationCoordinate2D) {
        service.request(.search(lat: coordinate.latitude, long: coordinate.longitude)) { [weak self] (result) in
            guard let strongSelf = self else { return }
            switch result {
            case .success(let response):
                let root = try? strongSelf.jsonDecoder.decode(Root.self, from: response.data)
                let viewModels = root?.businesses
                    .compactMap(StoreListViewModel.init)
                    .sorted(by: { $0.distance < $1.distance})
                if let nav = strongSelf.window.rootViewController as? UINavigationController,
                    let storeListViewController = nav.topViewController as? StoreTableViewController {
                    storeListViewController.viewModels = viewModels ?? []
                } else if let nav = strongSelf.storyboard
                    .instantiateViewController(withIdentifier: "StoreNavigationController") as?
                        UINavigationController {
                    strongSelf.navigationController = nav
                    strongSelf.window.rootViewController?.present(nav, animated: true) {
                        (nav.topViewController as? StoreTableViewController)?.delegate = self
                        (nav.topViewController as? StoreTableViewController)?.viewModels = viewModels ?? []
                    }
                }
            case .failure(let error):
                print("Error: \(error)")
            }
        }
    }
}

extension AppDelegate: LocationActions, ListActions {
    func didTapAllow() {
        locationService.requestLocationAuthorization()
    }

    func didTapCell(_ viewController: UIViewController, viewModel: StoreListViewModel) {
        loadDetails(for: viewController, withId: viewModel.id)
    }
}

Is there anything I'm missing or need to add/change?

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
moyo.clive22
  • 61
  • 1
  • 2

1 Answers1

7

Welcome to Stackoverflow!

First off, try going back to studying that networking library Moya. Here are the examples of its usage: https://github.com/Moya/Moya/tree/master/docs/Examples


So basically your question is how to add parameters in Moya?

Well that's quite easy, especially if you have a good grasp of using Moya.

Let's add the parameter term. I will let you add the other parameter categories by yourself after this answer.

In your enum BusinessProvider, there's a case search, right? And you already can see two existing parameters, why don't we add a new param called term?

case search(lat: Double, long: Double, term: String)

Since you are adding the parameter in your task, not in path, then let's go to the task variable. Remember you can add the params in the task but its more practical to do it in the `task.

Let's add the new param in the search task

case let .search(lat, long, term):
            return .requestParameters(
                parameters: [ "latitude": lat, "longitude": long, "term": term, "limit": 30], encoding: URLEncoding.queryString)

Voila! You now have a new term param in your search case.

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95