SwiftUI:如何使用组合进行 POST API 调用?

发布于 2025-01-13 00:06:54 字数 3372 浏览 1 评论 0原文

首先,请检查我的代码。

这是 Dataservice Utility

import Foundation
import Combine
import SwiftUI

class PapagoDataService {
    
    @Published var translated : TranslateModel?
    
    static let instance = PapagoDataService()
    
    var cancellables = Set<AnyCancellable>()
    
    private init() {
        apiCall(text: "안녕하세요")
    }
    
    private func apiCall(text : String) {
        
        let param = "source=ko&target=en&text=\(text)"
        let paramData = param.data(using: .utf8)
        let client_Id = "************"
        let client_Secret = "********"

        guard let url = URL(string: "https://openapi.naver.com/v1/papago/n2mt")
        else { return }
        print("0")
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = paramData
        request.addValue(client_Id, forHTTPHeaderField: "X-Naver-Client-Id")
       
        
        print("1")
        URLSession.shared.dataTaskPublisher(for: url)
            .subscribe(on: DispatchQueue.global(qos: .background))
            .tryMap(handleOutput)
            .decode(type: TranslateModel.self, decoder: JSONDecoder())
            .sink { (completion) in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print("Error to download")
                }
            } receiveValue: { [weak self] (translatedData) in
                self?.translated = translatedData
            }
            .store(in: &cancellables)
    }
    
    func handleOutput(output : URLSession.DataTaskPublisher.Output) throws -> Data {
        
        guard let response = output.response as? HTTPURLResponse,
              response.statusCode >= 200 && response.statusCode < 300  else {
                  throw URLError(.badServerResponse)
              }
        return output.data
    }
    
}

第二个是 ViewModel

import Foundation
import Combine

class HomeViewModel : ObservableObject {
    
    @Published var translated : TranslateModel?
    
    let dataService = PapagoDataService.instance
    
    var cancellable = Set<AnyCancellable>()
    
    init() {
        addSubscriber()
    }
    
    private func addSubscriber() {
        dataService.$translated
            .sink { [weak self] (receiveModel) in
                DispatchQueue.main.async {
                    self?.translated = receiveModel
                }
            }
            .store(in: &cancellable)
    }
}

最后,这是数据模型

import Foundation

struct TranslateModel : Codable {
    
    let message: Message
}

// MARK: - Message
struct Message: Codable {
    
    let type, service, version: String
    let result: Result

    enum CodingKeys: String, CodingKey {
        case type = "@type"
        case service = "@service"
        case version = "@version"
        case result
    }
}

// MARK: - Result
struct Result: Codable {
    let translatedText: String
}

在此处输入图像描述

我尝试通过这种方式进行 POST API 调用。 但是,我在 DataService 类上收到错误 请检查这张图片。

在我看来,URLsession是错误的,但我不知道问题出在哪里。

我希望我能通过这个问题来理解 api 调用与合并! 谢谢。

Firstly, Please check my code.

This is Dataservice Utility

import Foundation
import Combine
import SwiftUI

class PapagoDataService {
    
    @Published var translated : TranslateModel?
    
    static let instance = PapagoDataService()
    
    var cancellables = Set<AnyCancellable>()
    
    private init() {
        apiCall(text: "안녕하세요")
    }
    
    private func apiCall(text : String) {
        
        let param = "source=ko&target=en&text=\(text)"
        let paramData = param.data(using: .utf8)
        let client_Id = "************"
        let client_Secret = "********"

        guard let url = URL(string: "https://openapi.naver.com/v1/papago/n2mt")
        else { return }
        print("0")
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = paramData
        request.addValue(client_Id, forHTTPHeaderField: "X-Naver-Client-Id")
       
        
        print("1")
        URLSession.shared.dataTaskPublisher(for: url)
            .subscribe(on: DispatchQueue.global(qos: .background))
            .tryMap(handleOutput)
            .decode(type: TranslateModel.self, decoder: JSONDecoder())
            .sink { (completion) in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print("Error to download")
                }
            } receiveValue: { [weak self] (translatedData) in
                self?.translated = translatedData
            }
            .store(in: &cancellables)
    }
    
    func handleOutput(output : URLSession.DataTaskPublisher.Output) throws -> Data {
        
        guard let response = output.response as? HTTPURLResponse,
              response.statusCode >= 200 && response.statusCode < 300  else {
                  throw URLError(.badServerResponse)
              }
        return output.data
    }
    
}

Second one is ViewModel

import Foundation
import Combine

class HomeViewModel : ObservableObject {
    
    @Published var translated : TranslateModel?
    
    let dataService = PapagoDataService.instance
    
    var cancellable = Set<AnyCancellable>()
    
    init() {
        addSubscriber()
    }
    
    private func addSubscriber() {
        dataService.$translated
            .sink { [weak self] (receiveModel) in
                DispatchQueue.main.async {
                    self?.translated = receiveModel
                }
            }
            .store(in: &cancellable)
    }
}

Last, This is Model of data

import Foundation

struct TranslateModel : Codable {
    
    let message: Message
}

// MARK: - Message
struct Message: Codable {
    
    let type, service, version: String
    let result: Result

    enum CodingKeys: String, CodingKey {
        case type = "@type"
        case service = "@service"
        case version = "@version"
        case result
    }
}

// MARK: - Result
struct Result: Codable {
    let translatedText: String
}

enter image description here

I tried to do POST API Call with combine by this way.
But, I got the error on DataService Class
Check this Picture please.

In my opinion, URLsession is wrong, but I don't know what is the problem.

I hope I can serve this problem to understand api call with combine!
Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

薄暮涼年 2025-01-20 00:06:55

在您的 private func apiCall(text : String) {...} 中使用 request,如下所示:

 URLSession.shared.dataTaskPublisher(for: request)  // <--- here

PS:不要显示您的 client_Secret在您的代码中,立即删除它

in your private func apiCall(text : String) {...} use the request, like this:

 URLSession.shared.dataTaskPublisher(for: request)  // <--- here

PS: do not show your client_Secret in your code, remove it now.

一抹苦笑 2025-01-20 00:06:55

在您的代码中检查您是否正在创建请求但没有在任何地方使用它。

使用:URLSession.shared.dataTaskPublisher(for request: URL Request)

您正在调用 url,而不是请求。

In your code check that you are creating request but not using it any where.

Use: URLSession.shared.dataTaskPublisher(for request: URL Request)

You are making calling for url not for the request.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文