Using Moya

  1. API End Point
//
//  API.swift
//  MoyaAPIDemo
//
//  Created by Joynal Abedin on 19/10/23.
//

import Foundation
import Moya
import UIKit

enum APIEndpoint {
    case bookList
    case searchBook(name: String)
    case uploadImage(formfile: UIImage)
    case uploadImageWithIdentifier(formfile: UIImage, filecode: String)
}

extension APIEndpoint: TargetType {
    var baseURL: URL {
        guard let url = URL(string: "https://devilarticle.com") else {
            fatalError()
        }
        return url
    }
    
    var path: String {
        switch self {
        case .bookList:
            return "/api/LibraryService/GetAllBook"
        case .searchBook:
            return "/api/LibraryService/SearchBook"
        case .uploadImage:
            return "/priceTrackApp/api/Product/UploadImage"
        case .uploadImageWithIdentifier:
            return "/priceTrackApp/api/Product/UploadImageWithIdentifier"
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .bookList:
            return .get
        case .searchBook:
            return .get
        case .uploadImage:
            return .post
        case .uploadImageWithIdentifier:
            return .post
        }
    }
    
    var task: Task {
        switch self {
        case .bookList:
            return .requestPlain
            
        case .searchBook(let name):
            return .requestParameters(parameters: ["name": name], encoding: URLEncoding.queryString)
            
        case .uploadImage(let image):
            let imageData = image.jpegData(compressionQuality: 0.25)
            let formData: [Moya.MultipartFormData] = [Moya.MultipartFormData(provider: .data(imageData!), name: "formFile", fileName: "user.jpeg", mimeType: "image/jpeg")]
            return .uploadMultipart(formData)
            
        case .uploadImageWithIdentifier(let image, let code):
            var params = [String:Any]() ///`parameter`
            params["filecode"] = code
            
            var formData = [MultipartFormData]() /// `body` data , `image` data
            let imageData = image.jpegData(compressionQuality: 0.25)
            
            formData.append(MultipartFormData(provider: .data(imageData!), name: "formFile", fileName: "user.jpeg", mimeType: "image/jpeg"))
            
            return .uploadCompositeMultipart(formData, urlParameters: params)
        }
    }
    
    var headers: [String : String]? {
        switch self {
        case .uploadImage, .uploadImageWithIdentifier:
            return ["Content-type" : "multipart/form-data"]
        default:
            return ["Content-Type": "application/json"]
        }
    }
    
    var sampleData: Data {
        return Data()
    }
}

2. API Service

//
//  NetworkManager.swift
//  MoyaAPIDemo
//
//  Created by Joynal Abedin on 19/10/23.
//

import Foundation
import Moya
import UIKit

protocol Networkable {
    var provider: MoyaProvider<APIEndpoint> { get }
    func fetchBooks(completion: @escaping (Result<Response, Error>) -> ())
    func searchBook(name: String, completion: @escaping (Result<Response, Error>) -> ())
    func uploadImage(formfile: UIImage, completion: @escaping (Result<ImageResponse, Error>) -> ())
    func uploadImageWithIdentifier(formfile: UIImage, code: String, completion: @escaping (Result<ImageResponse, Error>) -> ())
}

class APIService: Networkable {
    var provider = MoyaProvider<APIEndpoint>(plugins: [NetworkLoggerPlugin()])
    
    func fetchBooks(completion: @escaping (Result<Response, Error>) -> ()) {
        request(target: .bookList, completion: completion)
    }
    
    func searchBook(name: String, completion: @escaping (Result<Response, Error>) -> ()) {
        request(target: .searchBook(name: name), completion: completion)
    }
    
    func uploadImage(formfile: UIImage, completion: @escaping (Result<ImageResponse, Error>) -> ()) {
        request(target: .uploadImage(formfile: formfile), completion: completion)
    }
    
    func uploadImageWithIdentifier(formfile: UIImage, code: String, completion: @escaping (Result<ImageResponse, Error>) -> ()) {
        request(target: .uploadImageWithIdentifier(formfile: formfile, filecode: code), completion: completion)
    }
}

private extension APIService {
    private func request<T: Decodable>(target: APIEndpoint, completion: @escaping (Result<T, Error>) -> ()) {
        provider.request(target) { result in
            switch result {
            case let .success(response):
                do {
                    let results = try JSONDecoder().decode(T.self, from: response.data)
                    completion(.success(results))
                } catch let error {
                    completion(.failure(error))
                }
            case let .failure(error):
                completion(.failure(error))
            }
        }
    }
}

3. Response Model

//
//  Response.swift
//  MoyaAPIDemo
//
//  Created by Joynal Abedin on 19/10/23.
//

import Foundation

struct Response: Codable {
    var responseCode: Int
    var result: String
    var errormessage: String?
    var data: [BookList]
}

struct BookList: Codable {
    var id: Int
    var bookId: Int
    var bookName: String
    var availableCopyNumber: Int
}

struct ImageResponse: Codable {
    var responseCode: Int
    var result: String
    var errormessage: String?
}

4. Get Data

//
//  ContentView.swift
//  MoyaAPIDemo
//
//  Created by Joynal Abedin on 19/10/23.
//

import SwiftUI
import Alamofire

struct ContentView: View {
    
    private var bookListArray: [Response] = []
    private let apiService: APIService = APIService()
    
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
                .onTapGesture {
                    uploadImageWithidentifier()
                }
        }
        .padding()
    }
    
    func loadUsers() {
        //startLoading()
        apiService.searchBook(name: "code") { result in
            //guard let weakSelf = self else { return }
            //weakSelf.stopLoading()
            switch result {
            case .success(let bookListArray):
                print(bookListArray)
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }
    
    ///Upload `image`
    func uploadImage() {
        //startLoading()
        apiService.uploadImage(formfile: UIImage(named: "user")!) { result in
            //guard let weakSelf = self else { return }
            //weakSelf.stopLoading()
            switch result {
            case .success(let status):
                print(status.result)
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }
    
    ///Upload `image`
    func uploadImageWithidentifier() {
        //startLoading()
        apiService.uploadImageWithIdentifier(formfile: UIImage(named: "user")!, code: "669977") { result in
            //guard let weakSelf = self else { return }
            //weakSelf.stopLoading()
            switch result {
            case .success(let status):
                print(status.result)
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }
    
}

#Preview {
    ContentView()
}