Giter Club home page Giter Club logo

swiftui-dogbreeds-rest-api's Introduction

Dog API

Xcode Version 13.0

SwiftUI, Alamofire, ObjectMapper, AlamofireObjectMapper, Kingfisher

I pick Dog-API to improve my REST API skill because I could not do it in a progrmming test some months ago. The Alamofire and ObjectMapper make my life much easier. The code is also shorter and clean.

The idea

  1. Featch data form Dog-API with Alamofire only when the App loaded and use ObjectMapper save to Model object [BreedModel].
  2. Use @EnvironmentObject var dogVM: BreedVM to pass values between views.
  3. Check orientation mode with SceneDelegate then save to @AppStorage.
  4. Use StaggeredGrid helper view for the better GridView.

SwiftUI-DogBreeds-REST-API

| | |

How to setup project

  1. Clone project to your Mac
  2. run pod install in Terminal
 run pod install

After you install you will see Podfile

  pod 'Alamofire', '~> 4.7'
  pod 'ObjectMapper', '~> 3.5'
  pod 'Kingfisher', '~> 6.0'
  pod 'AlamofireObjectMapper', '~> 5.2'

Setup Scene Delegate

Note : The orentation is detected by Scene Delegate and Xcode 13 you may notice it doesn’t have an Info.plist file. See setup below to get Info.plist .

You will put @AppStorage to every view that you want to be rotated.

@AppStorage("isPortrait") private var isPortrait: Bool = false
  1. Go to Application Scene Minifest -> Scene Configuration -> Application Role
  2. Delegate Class Name put $(PRODUCT_MODULE_NAME).SceneDelegate
  3. Configuration Name put Default Configuration
  4. Set Allow Arbitrary Loads -> App Transport Security Settings for requst API.

Check these files

Constants.swift

public let baseURL: URL = URL(string: "https://dog.ceo")! //This will never fail
public let apiURL: URL = baseURL.appendingPathComponent("api")

public let kBreedsListURL: URL = apiURL.appendingPathComponent("breeds/list")
public let kBreedsListAllURL: URL = apiURL.appendingPathComponent("breeds/list/all")
public func kImagesByBreedURL(for breedName: String) -> URL {
    return apiURL.appendingPathComponent("/breed/\(breedName)/images")
}

BreedsModel.swift

import Foundation

struct FetchImageModel: Identifiable,Hashable {
    var id: String
    let imageUrl: String
}

struct FetchBreedModel: Identifiable,Hashable {
    var id: String
    var nameOfDog: String
}

 
struct BreedModel: Identifiable, Hashable {
    var id: String
    var nameOfDog: String
    var thumbnail: String
    var isFavorite: Bool
    var imageUrls: [FetchImageModel]
}

ObjectMapper.swift

import SwiftUI
import ObjectMapper
import AlamofireObjectMapper

// Note: - Map response form https://dog.ceo/api/breeds/list/all
class BreedsListAllResponse: Mappable {
    
    var status: String = ""
    var breeds: [FetchBreedModel] = []
    
    required init?(map: Map){
        
        if let breedsStr: [String:Any] = try? map.value("message") {
            for breed in breedsStr {
                    
                    let subBreedItems = breed.value as! [String]
                    
                    if (subBreedItems.count > 0) {
                        for item in subBreedItems {
                            breeds.append(FetchBreedModel(id: UUID().uuidString, nameOfDog: "\(breed.key) \(item)"))
                        }
                    } else {
                        breeds.append(FetchBreedModel(id: UUID().uuidString, nameOfDog: breed.key))
                    }
            }
        }
    }
    
    func mapping(map: Map) {
        status <- map["status"]
    }
}

// Note: - Map response form https://dog.ceo/api/breeds/list/
struct BreedsListResponse: Mappable {

    var breeds: [FetchBreedModel] = []
    var status: String = ""

    init?(map: Map) {
      
        if let breedsStr: [String] = try? map.value("message") {
            self.breeds = breedsStr.map { FetchBreedModel(id: UUID().uuidString, nameOfDog: $0) }
        }
         
    }

    mutating func mapping(map: Map) {
        status <- map["status"]
    }
}

// Note: - Map response from https://dog.ceo/api/breed/affenpinscher/images
struct ImagesByBreedResponse: Mappable {

    var images: [FetchImageModel] = []
    var status: String = ""

    init?(map: Map) {
        if let imagesStr: [String] = try? map.value("message") {
            self.images = imagesStr.map { FetchImageModel(id: UUID().uuidString, imageUrl: $0) }
        }
    }

    mutating func mapping(map: Map) {
        status <- map["status"]
    }
}

BreedVM.swift

class BreedVM : ObservableObject {
     
    @Published var contentRows: [BreedModel] = []
    @Published var selectedRow: BreedModel?
    @Published var favoriteBreeds: [BreedModel] = []
    
    init(){
        getDogBreedInfo()
    }
    
    func getDogBreedInfo(){
        
        self.getAllBreed { breedRows in
            
            for breed in breedRows {
                
                self.getBreedImages(nameOfDog: breed.nameOfDog) { breedImages in
                    // Note: - Every App loaded will have random thumbnail
                    var thumbnail: String = ""
                    if let image = breedImages.randomElement() {
                        thumbnail =  image.imageUrl
                    }
                    if breedImages.count > 0 {
                        self.contentRows.append(BreedModel(id: UUID().uuidString,
                                                            nameOfDog: breed.nameOfDog,
                                                            thumbnail: thumbnail,
                                                            isFavorite: false,
                                                            imageUrls: breedImages))
                    }
                   
                }
            }
        }
         
    }
    
    func setFavoriteByObjectId(objectId: String) {
        if let index = contentRows.firstIndex(where: { $0.id == objectId }) {
            contentRows[index].isFavorite.toggle()
        }
    }
    
}
// Note: - Featch Data from APIs

extension BreedVM {
    
    func getAllBreedsWithSubBread(completion: @escaping ([FetchBreedModel]) -> Void) {
        // Note: - Map reponse data with BreedsListAllResponse
        Alamofire.request(kBreedsListAllURL).responseObject { (response: DataResponse<BreedsListAllResponse>) in
            let breedsResponse = response.result.value
            completion(breedsResponse?.breeds ?? [])
        }
    }
    
    func getAllBreed(completion: @escaping ([FetchBreedModel]) -> Void) {
        // Note: - Map reponse data with BreedsListResponse
        Alamofire.request(kBreedsListURL).responseObject { (response: DataResponse<BreedsListResponse>) in
            let breedsResponse = response.result.value
            completion(breedsResponse?.breeds ?? [])
        }
    }

    func getBreedImages(nameOfDog: String, completion: @escaping ([FetchImageModel]) -> Void) {
        // Note: - Map reponse data with ImagesByBreedResponse
        let url = kImagesByBreedURL(for: nameOfDog)
        
        Alamofire.request(url).responseObject { (response: DataResponse<ImagesByBreedResponse>) in
            let breedsResponse = response.result.value
            completion(breedsResponse?.images ?? [])
        }
    } 
     
}

swiftui-dogbreeds-rest-api's People

Contributors

waleerat avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.