Multiple encoding types for Alamofire Request - alamofire

I need to make a POST request with an HTTP Body with a JSON object, but I also need to use url query parameters in the same request.
POST: http://www.example.com/api/create?param1=value&param2=value
HTTP Body: { foo : [ bar, foo], bar: foo}
Is this supported by Alamofire? How would I go about doing this?

This is definitely a valid use case. I've ran into similar issues with trying to append access tokens as query parameters to a POST request. Here's a function that should make things a bit easier for the time being that is similar to your approach.
func multiEncodedURLRequest(
method: Alamofire.Method,
URLString: URLStringConvertible,
URLParameters: [String: AnyObject],
bodyParameters: [String: AnyObject]) -> NSURLRequest
{
let tempURLRequest = NSURLRequest(URL: NSURL(string: URLString.URLString)!)
let URLRequest = ParameterEncoding.URL.encode(tempURLRequest, parameters: URLParameters)
let bodyRequest = ParameterEncoding.JSON.encode(tempURLRequest, parameters: bodyParameters)
let compositeRequest = URLRequest.0.mutableCopy() as NSMutableURLRequest
compositeRequest.HTTPMethod = method.rawValue
compositeRequest.HTTPBody = bodyRequest.0.HTTPBody
return compositeRequest
}
With that said, could you make sure to put in a feature request issue on the Github? This is certainly something we need to figure out how to make easier in Alamofire since it's such a common use case. If you could put in a really good description of your use case, then I'm sure it will get attention. I will certainly help press to get support added.

At this point, I've decided to solve this by manually encoding an NSURLRequest with the URL parameters, retrieving the URL from that request, and using that to create the final request. I've created a function to return the query parameter encoded request:
private func queryParameterEncodedRequestURL(urlString: String,
values: [String]) -> NSURL {
let URL = NSURL(string: urlString)
var request = NSURLRequest(URL: URL)
let parameters = [
"param1": values[0]!,
"param2": values[1]!
]
let encoding = Alamofire.ParameterEncoding.URL
(request, _) = encoding.encode(request, parameters: parameters)
return (request.URL, nil)
}
This works fine, but I would definitely like to see Alamofire support multiple encoding types more easily. This feels like a workaround to me.

Related

Ktor Client, how to specify body parameters

I'm trying to send a POST request to the server, this post requires parameters "email" and "password".
but I don't know how to specify parameters, I read the documentation but I didn't understand.
this is my code:
val request=client.post<String> {
url(BASE_URL+"login.php")
body="email=$email,password=$password"
}
fwiw I use something like following here....though I would have thought specifying url like you do should also work. What issue do you see? The body might also be some json for example, or maybe a data class etc if you have serialization setup.
response = client.post(url) {
body = "some params/data etc"
}
It should work if you use serialization, but I solved my problem by using 'Uploading multipart/form-data'
val request=client.post(url) {
body=MultiPartFormDataContent(formData {
append("email","data")
append("password","data")
})
}
see Documentation

Update response body content using HttpClientFeature

Using a HttpClientFeature implementation with responsePipeline.intercept seems the right way to change an HTTP response.
However, I do not understand how to update the response body. Especially I don't understand how to wrap the new HttpResponse to be passed in to proceedWith.
You can use the HttpResponseContainer to proceed with a new response body:
client.responsePipeline.intercept(HttpResponsePipeline.Transform) { (info, body) ->
val newBody = "test"
proceedWith(HttpResponseContainer(info, newBody))
}

using active campaign api with swift and Alamofire

Im fairly new to iOS development and I'm working on a project that requires integration with Active Campaign.
I simply want to make a post request using their API to add a contact to the database when a button is pressed.
I've first attempted a get request for the current contacts using Alamofire to make sure I can get to it and I can't seem to get the desired output. I've searched and googled quite a bit to find a solution. I've found a few different ways to do it online but nothing has seemed to work.
When I run my current code to add a contact I get this error:
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(error: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
Below is my code to add a contact. I will say this is after trying many different solutions I've come across and I may have confused myself. Any help is much appreciated!!
import UIKit
import Alamofire
import SwiftyJSON
class emailEntry: UIViewController {
#IBOutlet weak var f_name: UITextField!
#IBOutlet weak var l_name: UITextField!
#IBOutlet weak var email: UITextField!
#IBOutlet weak var center_frame: UIView!
var api_key = "MY_KEY_IS_HERE"
let urlBase = "BASE_URL_HERE"
#IBAction func submit_but(_ sender: UIButton) {
let url = "\(urlBase)/admin/api.php?api_action=contact_add"
guard let authHeader = Request.authorizationHeader(user: "AnyString", password: api_key) else{
print("Nothing")
return
}
let parameters:Parameters = ["first_name":f_name,
"last_name":"l_name",
"email":"email"
]
let headers:HTTPHeaders = [authHeader.key: authHeader.value]
Alamofire.request(url, method: .post , parameters: parameters, headers: headers).validate().responseJSON { response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
}
}
That error indicates the response you got back was not JSON. Most likely it was some sort of HTML error page. Check the API docs and make sure you're properly formatting your request. Also, you can use responseString to see the content of the response in plain text.

Alamofire returning status Failure Always

I am using Alamofire in my App. This is my Alamofire request code
let params: [String:AnyObject] = ["email": self.signin_Email.text!, "password": self.signin_Password.text!]
Alamofire.request(.GET, "http://DomainName/api/App/Sign_Up", parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
when i put debugPrint(reponse)
what i got is this
[Request]: { URL:
http://Domain/api/App/Sign_Up } [Response]: nil [Data]:
0 bytes [Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-1017
"cannot parse response" UserInfo={NSUnderlyingError=0x7ffe0840e700
{Error Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)"
UserInfo={_kCFStreamErrorCodeKey=-1, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://Domain/api/App/Sign_Up,
NSErrorFailingURLKey=http://Domain/api/App/Sign_Up,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1, NSLocalizedDescription=cannot parse response}
Here i am always getting the response status as Failure. I am not able to figure out what's going on. (using mvc4 as backend).
This is the Api method that accepts the above given request and returns a JSON Data
[System.Web.Http.HttpGet]
public JsonResult Sign_Up(string email,string password)
{
email = email;
password = password;
System.Web.Mvc.JsonResult usertoreturn = new System.Web.Mvc.JsonResult();
SignUpViewModel signupviewmodel = new SignUpViewModel();
usermodeltocheck.SetPassword(password);
usermodeltocheck.MembershipDate = DateTime.Now;
usermodeltocheck.IsMember = true;
usermodeltocheck.PublicKey = Guid.NewGuid().ToString("N");
usermodeltocheck.MembershipStatus = true;
usertoreturn.Data = Helper.UpdateUser(usermodeltocheck);
}
usertoreturn.JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet;
return usertoreturn;
}
UPDATE #1 I have created a new method named test that accepts a parameter.The method just returns the parameter value .I tried the sample code available in Github and its working. I am able to get proper response if I am avoiding parameters argument in Alamofire request Method. like
Alamofire.request(.GET, "http://DomainName/api/App/Test", encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
here I am getting a SUCCESS response. I have updated my code like this
Alamofire.request(.GET, "http://DomianName/api/App/Test?test=testing", encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
here also I am getting SUCCESS response. The Error occurs when I pass parameter value to the argument parameters parameters: ["test":"testing"].
also I set my parameters like this
let params = ["test":"testing"]
Alamofire.request(.GET, "http://DomianName/api/App/Test", parameters : params ,encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
in this way also i am getting my response to FAILURE
May be its not an answer you are looking for but for me removing a parameter from Alamofire request method did the trick. Here is the change:
let params : [String:AnyObject] = ["email":self.signin_Email.text!,"password":self.signin_Password.text!]
let request = Alamofire.request(.GET, "http://DomianName/api/App/Sign_Up", parameters: params).responseJSON{
response in
switch response.result{
case .Success(let data) :
let json = JSON(data)
print(json)
case .Failure(let error):
print("Error : \(error)" )
}
}
I have removed encoding:.JSON from my Alamofire request method parameter list and that's it...
Try to print out all the data in response using the following:
let URLString = "http://DomainName/api/App/Sign_Up"
Alamofire.request(.GET, URLString, parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
Once you print it out, if you could update your question, we could help further. I'll update my answer accordingly afterwards. 👍🏼
Update #1
Okay, so the NSURLErrorDomain Code=-1017 points out that your server is most likely misbehaving. Are you able to successfully use cURL, Postman, Paw or some other HTTP client to hit the service? Once you get one of those working, you should use debugPrint on the `request object to compare.
let URLString = "http://DomainName/api/App/Sign_Up"
let request = Alamofire.request(.GET, URLString, parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
debugPrint(request)
This will show you the cURL command for the request.
I know this is kind of old but I stumbled upon this looking for something else. From what I have seen, I tend to get errors in this situation any time params are passed as JSON encoded with a .GET instead of a .POST
Changing the server to take a post for the URI makes everything flow correctly, and I guess in theory that is correct behavior, since if you aren't passing the values in the URL, you are technically posting the JSON to the endpoint.

How do I handle JSONP with WebAPI? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JSONP with MVC 4 WebApi
I have a get method for my WebAPI which is as follows:
private T Get<T>(string uri)
{
T result = default(T);
bool isSuccess = true;
client
.GetAsync(uri)
.ContinueWith(task =>
{
// EnsureStatus
isSuccess = task.Result.IsSuccessStatusCode;
task
.Result
.Content
.ReadAsAsync<T>()
.ContinueWith(t => result = t.Result)
.Wait();
})
.Wait();
return result;
}
The result is produced in a JSON format but I want it for JSONP.
I have read that ReadAsSync only handles built in mediaformatters. So is there a way I can change it to handle JsonP?
Stealing liberally from this duplicate....
To accomplish what you want you need three things :
to add a media formatter that outputs JSONP
register the media formatter (traditionally done through global.asx)
ensure the client requests jsonP.
You can steal this JSONP media formatter.
Then, you need to register the media formatter. You can do this programatically with the following code snippet:
var config = GlobalConfiguration.Configuration;
config.Formatters.Insert(0, new JsonpMediaTypeFormatter());
Since you apparently don't use global.asax you're going to need to make sure the formatter is registered somehow. YOU don't provide enough information on how to do it, but i suspect a judiciously placed IF statement and a static variable indicating registration would get you there.
I still don't quite know what type of client you're using, but if it's jquery something like the following will get you there:
$.ajax({
url: 'http://myurl.com',
type: 'GET',
dataType: 'jsonp',
success: function (data) {
alert(data.MyProperty);
}
})
The important part is the accept header sent matches the accept header your shiny new jsonp formatter is listening for. The top two choices in my opinion are either: application/javascript or text/javascript.