Как всегда отправлять параметры по умолчанию в HTTP-запрос, используя Moya / Alamofire? - PullRequest
0 голосов
/ 02 мая 2020

Мой сервер всегда требует, чтобы клиент отправил токен. Как разработчик, я могу забыть это. Теперь я хочу найти какое-то решение, которое заставляет меня не забывать посылать такие обязательные параметры (они могут расти в будущем, например, серверу может потребоваться язык устройства). Решение кажется довольно простым: у меня должно быть несколько ServerManager, которые получают параметры (например, ["user": "John"]) и URL-путь. И он также должен добавить обязательные параметры, например, ["token": "abscsdcds"]. Псевдокод будет выглядеть примерно так:

struct ServerManager {
     func request(params: [String: Any], path: String, completion: (ResponseModel) -> Void) {
          /// appending required default params 
          var paramsToSend = params
          paramsToSend["token"] = Token.token 

          /// making request here               

     }
}

Всякий раз, когда я делаю сетевой вызов, я могу использовать этот ServerManager с любым сомнением, которое отправляет все необходимые параметры и возвращает ответ.

Но все усложняется, потому что я использую Moya для работы в сети. Это сделано enumerations, который должен реализовать протокол TargetType. Я могу иметь десятки enums, такие как RateAPI, MovieAPI и др. c ... Это означает, что мой ServerManager должен принимать TargetType и HTTP-запрос, используя MoyaProvider. Вот оно:

 func request<T>(type: TargetType, completion: (ResponseModel<T>) -> Void) {
              /// appending required default params 
              moyaProvider.request(MultiTarget(type)) {  response in 
                     /// parse it 
              }              



         }

Я могу просто использовать вышеуказанную функцию, передавая TargetType, и она возвращает мне ответ. Я могу использовать вышеуказанную функцию следующим образом:

ServerManager.shared.request(target: MovieApi.list(params)) { (response) in

}

Но указанная выше params переменная всегда должна содержать токен. Это означает, что я должен писать params["token"] = "myToken" всякий раз, когда я делаю сетевой запрос. Это дублирование кода. Я думал создать какую-то базу RequestModel, которая будет содержать мои обязательные параметры. Тогда у меня могут быть разные подклассы RequestModel, которые добавляют свои поля к необходимым параметрам. Но это решение может быть легко введено в заблуждение (например, подкласс может отправлять свои собственные параметры, забывая о параметрах родительского класса).

Кажется, моя проблема в дизайне. Есть ли шаблон дизайна, который решает проблему выше? Или у нас есть встроенное решение в Moya / Alamofire, которое отправляет некоторые параметры по умолчанию для каждого запроса?

1 Ответ

1 голос
/ 02 мая 2020

Обычно серверный API получает токен из TTPHeaderFields, и с помощью Moya вы можете легко изменить defaultEndpointMapping в некоторый класс, например ApiGenerator , с помощью некоторого метода, например:

static func request<T : Decodable, E: TargetType>(targetApi : E, responseModel : T.Type, success successCallBack: @escaping (Response<T>) -> Void, error errorCallBack: @escaping (Error) -> Void) -> Disposable {
    ...

    }

И внутри этого метода:

let endpointClosure = { (target: E ) -> Endpoint in
            let defaultEndpoint = MoyaProvider.defaultEndpointMapping(for: target)
            let cookie = String(format: "JSESSIONID=%@;SPRING_SECURITY_REMEMBER_ME_COOKIE=%@", AppSettings.shared.setting.sessionId, AppSettings.shared.setting.rememberMeCookie )


            return defaultEndpoint.adding(newHTTPHeaderFields:
                [
                    "X-Client": "ios",
                    "Cookie" : cookie
                ]
            )
        }

и добавьте его к:

let provider = MoyaProvider<E>(endpointClosure: endpointClosure, plugins: [
            NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))])

И сделайте все остальное. Но в вашем случае я рекомендую создать ваш класс ApiGenerator и настроить в нем TargetApi.Task следующим образом:

switch defaultEndpoint.task {
   case .requestParameters(parameters: /*Append new params here*/ , encoding: JSONEncoding.default):
       ...
    default:
       ...
 }
...