Response Character Encoding - ktor

How can I explicitly set the character encoding (e.g. UTF-8) in a response?
call.respondText("Hello World!", ContentType.Text.Plain, HttpStatusCode.OK)

You can call the withCharset method on a ContentType object to create a copy with specified charset:
call.respondText("Hello World!", ContentType.Text.Plain.withCharset(Charsets.UTF_8), HttpStatusCode.OK)

Related

Swift SQL POST method - Why does it always create a response with <null> as the string?

I'm trying to set up POST requests to connect my Swift Project to my SQL server. I found a lot of good resources on how to create the POST requests, and my code seems to create the request fine. However, it always returns a null string instead of the desired output string. How can I get the request to submit with the correct string?
My POST function:
func addString() {
// declare the parameter as a dictionary that contains string as key and value combination. considering inputs are valid
let parameters: [String: Any] = ["textstring":"Testing..."]
// create the url with URL
let url = URL(string: "http://localhost:3000/strings")! // change server url accordingly
// create the session object
let session = URLSession.shared
// now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
// add headers for the request
request.addValue("application/json", forHTTPHeaderField: "Content-Type") // change as per server requirements
do {
// convert parameters to Data and assign dictionary to httpBody of request
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
return
}
// create dataTask using the session object to send data to the server
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print("Post Request Error: \(error.localizedDescription)")
return
}
// ensure there is valid response code returned from this HTTP response
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode)
else {
print("Invalid Response received from the server")
return
}
// ensure there is data returned
guard let responseData = data else {
print("nil Data received from the server")
return
}
do {
// create json object from data or use JSONDecoder to convert to Model struct
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: Any] {
print(jsonResponse)
// handle json response
} else {
print("data maybe corrupted or in wrong format")
throw URLError(.badServerResponse)
}
} catch let error {
print(error.localizedDescription)
}
}
// perform the task
task.resume()
}
My Object TextString that emulates the SQL table (Table "strings" has two columns: "id" (SERIAL PRIMARY KEY) and "textstring" (VARCHAR(255))
struct TextString: Codable, Hashable, Identifiable {
var id: Int
var textString: String
enum CodingKeys: String, CodingKey {
case id = "string_id"
case textString = "textstring"
}}
My response output:
["string_id": 28, "textstring": <null>]
I'm thinking that the issue is with the serialization but the code is taken almost directly from a youtube video where the test cases are shown and they work. Does anyone know why the output returns "textstring" as null and not "Testing..."?
Thanks in advance!

How can i exclude Keys in Object which are null to be returned in Json

i am wondering if there is a way to prevent a response to return keys in object that are null or null equivalent. I have for example a Response envelope and then the data payload and a sample response looks like this.
{
"success": true,
"errorCode": "",
"message": "JWT Token succesfull created",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidXNlcmlkIiwiU2NvcGUiOlsiQVRUQ1NSIiwiQVRUTFNSIl0sIm5iZiI6MTU4NDc0MjIzMiwiZXhwIjoxNTg0NzQzOTcyLCJpc3MiOiJodHRwOi8vc29hcGFwaS5wZ3RlbC5uZXQiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjU3NDY0In0.dWuETKdlfX4VzwWEP5XafZOpnFmSSCchQHUHi5GZ99E",
"expiration": "0001-01-01T00:00:00",
"scope": null
}
}
In this case expiration and scope are null expiration is a DateTime field.
Here is how i get to this response
Dim myResponse As New jsonResponse
myResponse.success = True
meResponse.errorCode = ""
myResponse.message = "JWT Token succesfull created"
Dim authCheck As New JSONWebTokenUtil
Dim accessList As New List(Of String)
accessList.Add("Sample1")
Dim Token = authCheck.GenerateJSONWebToken("userid", accessList, )
Dim myToken As New tokenResponse
myToken.token = Token
myResponse.data = myToken
Return myResponse
So since in the above case i dont set the scope or experation its null. Is there a way to be part of the out put if null or do i need to check each value and remove it if its null
I would try the following, from vb.net when you recive the json response, add the response to a string variable the with the replace's string method try to change the null value to a new value. I hope this be useful. Thank you. :)

Upload Multipart files Completion block

I'm using alamofire5 beta and I can't find the encodingResult that was used in previous versions.
This is my code function:
static func postComplexPictures(complexId: String, pictures: [UIImage], completion:#escaping (DataResponse<Data?>) -> Void) {
let url = K.ProductionServer.baseURL + "/api/v1/complex/" + complexId + "/pictures"
let token: String = UserDefaults.standard.string(forKey: "Token") ?? ""
let bearerToken: String = "Bearer " + token
let bundleId: String = Bundle.footballNow.bundleIdentifier!
let headers: HTTPHeaders = [HTTPHeaderField.authentication.rawValue: bearerToken,
HTTPHeaderField.contentType.rawValue: ContentType.multipart.rawValue,
HTTPHeaderField.bundleIdentifier.rawValue: bundleId]
AF.upload(multipartFormData: { (multipartFormData) in
for image in pictures {
if let imageData = UIImageJPEGRepresentation(image, 0.5) {
multipartFormData.append(imageData, withName: "pictures[\(index)]", fileName: "picture", mimeType: "image/jpeg")
}
}
}, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers).response(completionHandler: completion)
}
The .response actually calls my block, but it returns too quick for the images to be uploaded and I don't have a reference to the uploading status of the images.
Any thoughts?
Thanks!
I'm happy to say that there is no encoding result in Alamofire 5! Instead, failures in multipart encoding, and the async work required to encode it, are now part of the same request path as everything else. So you'll get any errors in your response calls, just like any other request. So if your request is finishing quickly, check the error, as the multipart encoding may have failed.

Alamofire Swift 3.0 Extra argument in call

I have migrated my project to Swift 3 (and updated Alamofire to latest Swift 3 version with pod 'Alamofire', '~> 4.0' in the Podfile).
I now get an "Extra argument in call" error on every Alamofire.request. Eg:
let patientIdUrl = baseUrl + nextPatientIdUrl
Alamofire.request(.POST, patientIdUrl, parameters: nil, headers: nil, encoding: .JSON)
Can anybody tell me why ?
According to Alamofire documentation for version 4.0.0 URL request with HTTP method would be followings:
Alamofire.request("https://httpbin.org/get") // method defaults to `.get`
Alamofire.request("https://httpbin.org/post", method: .post)
Alamofire.request("https://httpbin.org/put", method: .put)
Alamofire.request("https://httpbin.org/delete", method: .delete)
So your url request will be:
Alamofire.request(patientIdUrl, method: .post, parameters: nil, encoding: JSONEncoding.default, headers: nil)
and a sample request will be:
Alamofire.request(url, method: .post, parameters: param, encoding: JSONEncoding.default, headers: [AUTH_TOKEN_KEY : AUTH_TOKEN])
.responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // URL response
print(response.result.value as Any) // result of response serialization
}
Hope this helps!
This one worked for me. No need to remove encoding parameter
Update for Swift 5.x
Alamofire uses the Result type introduced in Swift 5.Also Alamofire.request has been changed to AF.request which will now read their switch response.result value with .success and .failure
AF.request("https://yourServiceURL.com", method: .get, parameters: [:], encoding: URLEncoding.default, headers: ["":""]).responseJSON { (response) in
switch response.result {
case let .success(value):
print(value)
case let .failure(error):
print(error)
}
}
Swift 3.x / 4.x
Alamofire.request("https://yourServiceURL.com", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(response.result.value)
}
break
case .failure(_):
print(response.result.error)
break
}
}
and make sure that the parameters are of type
[String:Any]?
In case of Get
Alamofire.request("https://yourGetURL.com", method: .get, parameters: ["":""], encoding: URLEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(response.result.value)
}
break
case .failure(_):
print(response.result.error)
break
}
}
Even works with
JSONEncoding.default
For Headers
If you are passing headers, make sure their type should be [String:String]
Go through the Parameter Encoding Link
https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md#parameter-encoding-protocol
Post method Alamofire 4.0 with Swift 3.0 and xCode 8.0
Alamofire.request(URL, method: .post, parameters: PARAMS)
.responseJSON { closureResponse in
if String(describing: closureResponse.result) == "SUCCESS"
{
// Sucess code
}
else
{
// Failure Code
}
}
My solution is if you are using headers, its type must be [String:String].
This error is up to parameters value. It has to be [String: String]
let url = URL(string: "http://yourURLhere")!
let params: [String: String] = ["name": "oskarko", "email": "youremail#here.com", "sex": "male"]
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil).validate(statusCode: 200..<600).responseJSON() { response in
switch response.result {
case .success:
var result = [String:String]()
if let value = response.result.value {
let json = JSON(value)
}
case .failure(let error):
print("RESPONSE ERROR: \(error)")
}
}
I just resolved the same problem as you have. The problem is I have imported Alamofire in the header, so I just remove the Alamofire when call request. Like that:
request(.POST, patientIdUrl, parameters: nil, headers: nil, encoding:
.JSON)
I hope it can help you.
I ran into this same Extra argument 'method' in call error when my URL variable was out of scope.
In your case, please make sure both baseUrl and nextPatientIdUrl are in scope when they are being used Alamofire.request(patientIdUrl,..) method.
Hopefully this resolves your issue. Thanks You!
func API()
{
if Reachability.isConnectedToNetwork()
{
let headers = ["Vauthtoken":"Bearer \(apiToken)"]
print(headers)
// let parameter = ["iLimit":"10","iOffset":"0","iThreadId":"1"]
ApiUtillity.sharedInstance.showSVProgressHUD(text: "Loding...")
Alamofire.request(ApiUtillity.sharedInstance.API(Join: "vehicle/CurrentVehicleLists"), method:.get, parameters:nil, headers: headers).responseJSON { response in
switch response.result {
case .success:
print(response)
ApiUtillity.sharedInstance.dismissSVProgressHUD()
let dictVal = response.result.value
let dictMain:NSDictionary = dictVal as! NSDictionary
let statusCode = dictMain.value(forKey: "status") as! Int
if(statusCode == 200)
{
}
else if statusCode == 401
{
}
else
{
}
case .failure(let error):
print(error)
ApiUtillity.sharedInstance.dismissSVProgressHUD()
}
}
} else
{
ApiUtillity.sharedInstance.dismissSVProgressHUD()
ApiUtillity.sharedInstance.showErrorMessage(Title: "Internet Connection", SubTitle: "Internet connection Faild", ForNavigation: self.navigationController!)
}
}
For me this is working.
For GET Request
Alamofire.request("http://jsonplaceholder.typicode.com/todos/1/get").responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print(response.result.value!)
}
break
case .failure(_):
print(response.result.error)
break
}
}
For POST
let parameters = NSDictionary(object: "nara", forKey: "simha" as NSCopying)
Alamofire.request("http://jsonplaceholder.typicode.com/posts", method: HTTPMethod.post, parameters: parameters as? Parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if response.result.value != nil{
print(response.result.value!)
}
break
case .failure(_):
print(response.result.error)
break
}
}
Thanks #Rajan Maheswari.
I fixed this issue with:
Reorder parameters (url then method type).
Change Encoding Enum to be "JSONEncoding.default" for example.
Note that: Alamofire methods signature change in Swift 3
Two things that I found worth noting.
Remove the first url label before its value. Use
Alamofire.request("https://yourServiceURL.com", method: .post,
instead of Alamofire.request(url: "https://yourServiceURL.com",
method: .post,.
Make sure the data type of the parameters is [String:
String]. Declare it explicitly.
I copy this code from Alamofire,create a URLRequest and used Alamofire.request(URLRequest) method, avoid this error
originalRequest = try URLRequest(url: url, method: method, headers: headers)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
I fixed this issue this way:
Just remove extra parameters, just parameters, encoding and headers, if these parameters are nil you can remove then and leave this way,
Alamofire.request(yourURLString, method: .post)
If you have added Alamofire files locally then don't use "Alamofire" before request
let apipath = “your api URL”
request(apipath, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseJSON { response in switch(response.result) {
case .success(_):
do {
let JSON = try JSONSerialization.jsonObject(with: response.data! as Data, options:JSONSerialization.ReadingOptions(rawValue: 0))
guard let JSONDictionary: NSDictionary = JSON as? NSDictionary else {
print("Not a Dictionary")
return
}
print("Post Response : \(JSONDictionary)")
}
catch let JSONError as NSError {
print("\(JSONError)")
}
break
case .failure(_):
print("failure Http: \(String(describing: response.result.error?.localizedDescription))")
break
}
}

Get server response message from error

My server (CakePHP) is responding like so:
$this->response->statusCode('400');
$this->response->type('json');
$this->response->body(json_encode(array('message' => 'Bookmark already exists')));
The Postman output looks like what you would expect:
{"message":"Bookmark already exists"}
The problem is that I cannot find a way to access this message from the failure handler (Alamofire 3.1.3 + SwiftyJSON 2.3.2)
Alamofire.request(.POST...
.validate()
.responseJSON { response in
switch response.result {
case .Success(_):
// All good
case .Failure(let error):
// Status code 400
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result)
I cannot find a way to cast response.data to JSON as a I simply get nil and the result returns just FAILURE.
Is there a way to access this server message from the failure handler ?
The data is not parsed in the .Failure case per the Alamofire 3.0 migration guide. However, server data is still available in response.data and can be parsed.
Below should work to parse this manually:
Alamofire.request(.POST, "https://example.com/create", parameters: ["foo": "bar"])
.validate()
.responseJSON { response in
switch response.result {
case .Success:
print("Validation Successful")
case .Failure(_):
var errorMessage = "General error message"
if let data = response.data {
let responseJSON = JSON(data: data)
if let message: String = responseJSON["message"].stringValue {
if !message.isEmpty {
errorMessage = message
}
}
}
print(errorMessage) //Contains General error message or specific.
}
}
}
This uses SwiftyJSON which provides the JSON struct to convert NSData. Parsing NSData to JSON can done without SwiftyJSON, answered here.
Another cleaner option might be to write a Custom Response Serializer.
A method with the router and no SwiftyJSON:
Alamofire.request(APIRouter.Register(params: params)).validate().responseJSON { response in
switch response.result {
case .Success(let json):
let message = json["clientMessage"] as? String
completion(.Success(message ?? "Success"))
case .Failure(let error):
var errorString: String?
if let data = response.data {
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String] {
errorString = json["error"]
}
}
completion(.Error(errorString ?? error.localizedDescription))
}
}
I have used the following lines to read the response body from a Alamofire request.
Alamofire.request(.POST, serveraddress, headers: headers, encoding: .JSON)
.response{ request, response, data, error in
let responseData = String(data: data!, encoding: NSUTF8StringEncoding)
print(responseData)
}
With this body I can get my custom server response errormessage.
best regards
For Alamofire 4.0 and above :
Try this
response.response?.statusCode
url : "YOUR-URL"
parameters: "YOUR PARAMETER DICTIONARY"
headers: "YOUR HEADER DICTIONARY"
I am using SwiftyJSON for JSON Parsing
A sample request is here :
func createPostRequestWith(path: String?,
parameters: [String : Any]? = nil,
success : #escaping (Any?) -> (),
failure : #escaping (NSError) -> ()) {
if !(Alamofire.NetworkReachabilityManager()?.isReachable)! {
let error = NSError(domain: "", code: -1003, userInfo: nil)
failure(error)
} else {
guard let url = path else { return }
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: createCurrentHeader()).validate(statusCode: 200..<300).responseJSON {
response in
switch response.result {
//Remove loader here either after parsing or on error
case .success(let data):
success(data)
case .failure(let error):
print(error)
if let responseData = response.data {
var parsedResponseData = JSON.init(data: responseData)
let customError = NSError(domain: parsedResponseData["message"].stringValue, code: response.response?.statusCode ?? 555, userInfo: nil)
failure(customError as NSError)
} else {
failure(error as NSError)
}
}
}
}
}