I'm new to iOS development with Swift, Moya, Alamofire, Argo, et al, so please be lenient with my ignorance.
I have read the documentation and searched the issues/questions but I'm still clueless as how to set the body of the HTTP request for a POST/PUT.
I have read about the endpoint closures (which don't seem the correct place for this) and about the request closures, but I still can't find an example of how to do it.
Forget for a second that I'm using other stuff for converting structs to/from json, and imagine that I already have a JSON string ready to set as the request body. Where/how should I set it?
I find it very strange that it is not prominently stated in the documentation, and that the only examples are for simple GET requests.
I appreciate any help.
Hey there! This is fairly straightforward, but our docs aren't great. We need to improve them. In your TargetType, use the parameters and method properties to return the JSON data and POST/PUT. Then, when setting up your provider, you can use a custom endpointsCosure to specify .JSON encoding for appropriate endpoints.
Let me know if that helps, and if you have any suggestions for improving our docs. Thanks for the great question!
Ok, I tried something like this: https://github.com/Moya/Moya/issues/403#issuecomment-182465029
and yes, the parameters are converted to JSON and used as the http body.
The thing is that I need to send a json body AND request parameters (as url query string).
Do you have any suggestions on how to achieve this?
Am I doing something fundamentally wrong that I'm the only one doing this?
Sounds complicated but not impossible. I haven't heard of an API requiring both an HTTP body _and_ query string parameters, usually it's one or the other.
Sounds like you need a custom parameter encoding. In my answer above I suggest using .JSON, but you'll need to use .Custom instead. We piggy-back on Alamofire's custom parameter encoding, so you should be able to follow their docs to create a custom param encoding to use in the endpointsClosure.
To be honest this is outside my experience – I'll try to help with an questions you have, just me know 👍
I stumbled across this issue trying to do something similar, we have an API where there are 'additional' params (sort, number of results to return etc) that are not part of the 'body'.
So we needed both URL parameter encoding for the query string, and a json body on the POST request.
Here is my solution for using the ParameterEncoding.CUSTOM, once I take a look at the Moya docs and find a good place for an example, I'll put in a pull request.
Define a typealias that adheres to Custom Encoding:
typealias MyAPICallCustomEncoding = (URLRequestConvertible, [String:AnyObject]?) -> (NSMutableURLRequest, NSError?)
Create a closure that implements Custom Encoding
let MyAPICallCustomEncodingClosure: MyAPICallCustomEncoding = { request, data in
let sort = NSURLQueryItem(name: "sort", value: "distance")
var req = request.URLRequest as NSMutableURLRequest
guard var components = NSURLComponents(string: req.URL!.absoluteString)
else {
// even though this is an error, Alamofire ignores the returned error.
return (req, nil)
}
//Create our query string params
components.queryItems = [sort]
req.URL = components.URL
//Add our JSON body
do {
let json = try NSJSONSerialization.dataWithJSONObject(data!, options: .PrettyPrinted)
req.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
req.HTTPBody = json
} catch {
return (req, nil)
}
return (req, nil)
}
Add the custom encoding to your API:
extension AuthedApi: TargetType {
var path: String {
case .MyAPICall:
return "/api/search"
}
var parameterEncoding: Moya.ParameterEncoding {
switch self {
case .MyAPICall:
return ParameterEncoding.Custom(MyAPICallCustomEncodingClosure)
}
}
As always, your milage may vary.
@m00sey Thanks for sharing your solution! :bow:
I have a similar question, how can I send an array as parameters?
[
"Foo",
"Bar"
]
Hey @retsohuang! We've updated our examples and here you can see it step by step. Hope it helps! If you have any questions/feedback about our examples, please let us know 🐼 Also, I think that this issue is resolved for now, so I'm closing it.
Most helpful comment
Hey there! This is fairly straightforward, but our docs aren't great. We need to improve them. In your
TargetType, use theparametersandmethodproperties to return the JSON data and POST/PUT. Then, when setting up your provider, you can use a customendpointsCosureto specify.JSONencoding for appropriate endpoints.Let me know if that helps, and if you have any suggestions for improving our docs. Thanks for the great question!