RESTful API Calls to Snowboy API with Swift 3 - swift

I'm a mobile app noobie currently trying to send 3 wav voice samples with Swift3 to the Snowboy API server.
Per their documentation Link Here, the request needs to have the following elements:
Endpoint: https://snowboy.kitt.ai/api/v1/train/
Type: POST
Content-Type: application/json
Required Parameter - token: Secret user token
Required Parameter - name: name of the recorded hotword that's mentioned in the voice samples
Required Parameter - voice_samples: A list of 3 voice samples in .wav format encoded as base64 strings
An example of the json they're expecting would look like this:
data = {
"name": "nameOfSample",
"language": "en",
"token": "token",
"voice_samples": [
{"wave": voicesample1asBase64String},
{"wave": voicesample2asBase64String},
{"wave": voicesample3asBase64String}
]
}
With the following code, I get a 400 status code. Meaning that it recognized the token parameter and authenticated my request but the latter is somehow malformatted:
lazy var session: URLSession = URLSession(configuration: self.conf)
let url: URL
init(url: URL){
self.url = url
}
func sendDataToURL (completion: #escaping JSONDictionaryHandler)
{
var request = URLRequest(url: self.url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let path1 = Bundle.main.path(forResource: "voicesample1", ofType: "wav")!
let path2 = Bundle.main.path(forResource: "voicesample2", ofType: "wav")!
let path3 = Bundle.main.path(forResource: "voicesample3", ofType: "wav")!
let paths = [path1, path2, path3]
let audioFileStrings = paths.map { (path: String) -> [String:String] in
let audioURL = URL(fileURLWithPath: path)
let filename = audioURL.lastPathComponent
if let base64String = try? Data(contentsOf: audioURL).base64EncodedString(){
//print(base64String)
return ["wave":base64String]
}else{return ["":""]}
}
let parameters = ["token": "XXXXXXXXXXXXXXX",
"name": "nameOfSample",
"language": "en",
"voice_samples": audioFileStrings
] as [String : Any]
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {return}
print("sending\(parameters)")
request.httpBody = httpBody
let uploadTask = session.dataTask(with: request) { (data, response, error) in
if error == nil {
if let httpResponse = response as? HTTPURLResponse{
print(httpResponse)
switch httpResponse.statusCode{
case 200: //successful
if let receiveddata = data{
print("YAAAY! DATA! \(receiveddata)")
do{
let json = try JSONSerialization.jsonObject(with: receiveddata, options: [])
print(json)
}
catch{
print(error)
}
}
default:
print("Bad HTTP response code: \(httpResponse.statusCode)")
}
}
if let receivedData = data{
}
}
else {
print("Error \(error?.localizedDescription)")
}
}
uploadTask.resume()
}
I think it's the voice_samples list that isn't well inserted in the son. Does anybody know how I can construct the request so the Snowboy server accepts it? Thanks!

You need a complete list of parameters. Add these:
age_group
gender
microphone
This these parameters i got 201 error. But i used bad wav files.
let parameters = ["token": "XXXXXXXX",
"name": "nameOfSample123123123",
"language": "en",
"voice_samples": audioFileStrings,
"age_group": "0_9",
"gender": "M",
"microphone": "test"

Related

Swift 5 - UrlSession - Post request starts with array

I am new about Swift. And I have question.I have to post a request starts with an array.
like this:
[{"columnName":"","columnLogic":"LIKE","columnValue":""}]
I tried with postman and return value which I wanted to.
Normally if it doesn't start with "[" and then I can post request and get back value. But Start with "[" and I tried many things not succeded :( please help me! I add my code which I use starts with "{" json post, this codes return error.`
private func getDataCars(){
struct Result: Codable {
let status: String
let document: DocumentStruct
}
struct DocumentStruct : Codable {
let pageno: Int
let total_count: String
let records: [RecordStruct]
}
struct RecordStruct: Codable{
let user_id:String
let user_name:String
let user_mail:String
let user_password:String
let user_phone:String
let user_durum:String
}
let parameters = [["columnName": "nameofcolumn", "columnLogic": "LIKE", "columnValue": "searchstring"]]
let url = URL(string: "http://getapiadress")!
let AuthTokenString = "somekey"
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Bearer " + AuthTokenString, forHTTPHeaderField: "Authorization")
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to data object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request, completionHandler: { data, response, error in
guard error == nil else {return}
guard let data = data else {return}
var result: Result?
do{
result=try JSONDecoder().decode(Result.self, from: data)
}
catch{
print("failed")
print(error)
}
guard let json = result else {
return
}
print(json.document.records[0].car_marka)
})
task.resume()
}`
here is my response of post request:
{
"status": "success",
"code": 1,
"message": "users found",
"document": {
"pageno": "1",
"pagesize": "30",
"total_count": "1",
"records": [
{
"user_id": "1",
"user_name": "Boss",
"user_mail": "boss#boss.com",
"user_password": "boss",
"user_phone": "123456789",
"user_durum": "admin"
}
]
}
}
If you want to send a dictionary as you mentioned at the beginning but you get a run-time error while trying to declare a JSON variable in XCode
[{"columnName":"","columnLogic":"LIKE","columnValue":""}]
Then in your code, you can do like this
// this is the dictionary format in Swift
let parameters = ["columnName": "","columnLogic": "LIKE","columnValue": ""]
do {
// This step will convert your dictionary to jsonData
let jsonData = try? JSONSerialization.data(withJSONObject: parameters)
request.httpBody = jsonData
} catch let error {
print(error.localizedDescription)
}
BUT Then if you want to make a POST request with an Array of objects then you can do something like this
struct ColumnInfo: Codable {
let columnName: String
let columnLogic: String
let columnValue: String
}
let parameters = [ColumnInfo(columnName: "nameofcolumn", columnLogic: "LIKE", columnValue: "searchstring")]
let url = URL(string: "http://getapiadress")!
let AuthTokenString = "somekey"
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Bearer " + AuthTokenString, forHTTPHeaderField: "Authorization")
do {
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
request.httpBody = try jsonEncoder.encode(parameters) // pass dictionary to data object and set it as request body
} catch let error {
print(error.localizedDescription)
}

How do I save the JSON data into my localhost? http post response says "200"

let parameters = ["lat": latitude, "lng": longitude]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
if let data = data {
do {
let jsonDecoder = JSONDecoder()
var parsedJSON = try jsonDecoder.decode([UserCoords].self, from: data)
parsedJSON.append(Vac_Pass.UserCoords(lat: latitude, lng: longitude))
let wer = try? JSONEncoder().encode(parsedJSON)
let json = try JSONSerialization.jsonObject(with: wer!, options: [])
print(json)
print(json)
} catch {
print(error)
}
}
}.resume()
Since the http post response says "200," this indicates that the request is successful but is not successful in uploading the new data. If the data did get uploaded, it would print out "201". I think there may be something wrong with my localhost web server.
The localhost is essentially a JSON file, which contains coordinates like this:
[
{"lat" : 38.8976, "lng" : -77.0369 } ,
{"lat" : 38.8980, "lng" : -77.0363 } ,
{"lat" : 38.8990, "lng" : -77.0367 }
]
Thank you - all inputs are appreciated :).

POST to Web API always returns nil

I'm just learning Web APIs with Swift.
And I've done as follows
Make some basic configuration
let session = URLSession(configuration: .default)
// Prepare URL #the URL is virtual now
let url = URL(string: "http://something.com/api")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
Set Post parameter
let parameters: [String: String] = [
"user_ID": "1",
]
let jsonData = try JSONEncoder().encode(parameters)
request.httpBody = jsonData
Take request to our web api
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
guard let data = data else { return }
do {
let myEnterprise = try JSONDecoder().decode(Enterprise.self, from: data)
print("Response data:\n \(myEnterprise)")
print("Response data:\n \(myEnterprise.returnData)")
} catch let jsonErr {
print(jsonErr)
}
}
task.resume()
myEnterprise is always nil. Can anyone help me?

Swift 4.2 code equivalent for SAP's Leonardo API [duplicate]

This question already has answers here:
Upload image with parameters in Swift
(3 answers)
Closed 4 years ago.
Getting HTTP 400 error while connecting with SAP Leonardo sandbox server using scene text recognition API
SAP provides boilerplate code in older version of swift. I have used curl command and the API and works. But its not working when I try and convert the code into swift 4.2 version. I am attaching the code below.
func connectWithSAP(photoURL : URL, photoData : String, sentImageData : Data){
if let myNewURL = URL(string: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition") {
var myRequest = URLRequest(url: myNewURL)
myRequest.addValue("multipart/form-data; --\(boundary)", forHTTPHeaderField: "Content-Type")
myRequest.addValue("application/json", forHTTPHeaderField: "Accept")
myRequest.addValue("xxxxxxxxxxx", forHTTPHeaderField: "APIKey")
myRequest.httpMethod = "POST"
myRequest.cachePolicy = .reloadIgnoringLocalCacheData
myRequest.timeoutInterval = 60.0
// Constructing the body of the request.
var data = Data()
var dataString = ""
dataString.append("--\(boundary)\r\n")
dataString.append(contentsOf: "Content-Disposition:form-data; name=\"files\"; filename=\"Image1.jpeg\" \r\n")
dataString.append(contentsOf: ";Content-Type:image/jpeg \r\n\r\n")
dataString.append(photoData)
dataString.append("--\(boundary) ----- \r\n")
data = dataString.data(using: .utf8)!
myRequest.httpBody = data
let task = URLSession.shared.dataTask(with: myRequest) { (data, response, error) in
if let error = error {
print(error)
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print(error as Any)
// Getting output at this stage, which is shown below
return }
if let mimeType = httpResponse.mimeType,
mimeType == "application/json",
let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]
print(json as Any)
}catch {
print(error)
}
}
}
task.resume()
}
I am getting a following details in my response object
{ URL: https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition } { Status Code: 400, Headers {\n Connection = (\n \"keep-alive\"\n );\n \"Content-Length\" = (\n 131\n );\n \"Content-Type\" = (\n \"application/json\"\n );\n Date = (\n \"Sat, 16 Feb 2019 11:56:37 GMT\"\n );\n Server = (\n \"Werkzeug/0.14.1 Python/3.5.5\"\n );\n \"Strict-Transport-Security\" = (\n \"max-age=31536000; includeSubDomains; preload;\"\n );\n \"X-Vcap-Request-Id\" = (\n \"fea7037c-4e48-49d2-4be1-53b0dad0ee46\"\n );\n}
As you would see the status code is HTTP 400. Need some help in getting the right response and data from the server.
Most probably, the body data got messed up. Here's the working code:
let boundaryConstant = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
let headers = [
"APIKey": "YourAPIKEY"
]
let contentType = "multipart/form-data; boundary=" + boundaryConstant
//API endpoint for API sandbox
var request = URLRequest(url: URL(string: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition")!)
//setting request method
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let path1 = Bundle.main.path(forResource: "your_image", ofType: "png")!
let url = URL(fileURLWithPath: path1)
let fileName = url.lastPathComponent
let data = try? Data(contentsOf: url)
let imageData = UIImage.init(data: data!)!
let pngData = UIImagePNGRepresentation(imageData)!
let mimeType = "image/png"
let boundaryStart = "--\(boundaryConstant)\r\n"
let boundaryEnd = "--\(boundaryConstant)--\r\n"
let fieldName = "files"
let contentDispositionString = "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n"
let contentTypeString = "Content-Type: \(mimeType)\r\n\r\n"
var body = Data()
body.append(boundaryStart.data(using: .utf8)!)
body.append(contentDispositionString.data(using: .utf8)!)
body.append(contentTypeString.data(using: .utf8)!)
body.append(pngData)
body.append("\r\n".data(using: .utf8)!)
body.append(boundaryEnd.data(using: .utf8)!)
request.httpBody = body
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.setValue(String(body.count), forHTTPHeaderField: "Content-Length")
let dataTask = session.dataTask(with: request) { (data, response, error) in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
}
dataTask.resume()
You can also use Alamofire to upload image. It's way cleaner, don't need to play around with "body" much:
let headers: HTTPHeaders = [
"APIKey": "<<Your API KEY>>",
"Content-type": "multipart/form-data"
]
let parameters:[String: String] = [:] //any other parameters you need to send
let path1 = Bundle.main.path(forResource: "<<your_image>>", ofType: "<<png or jpeg>>")!
let url = URL(fileURLWithPath: path1)
let fileName = url.lastPathComponent
let data = try? Data(contentsOf: url)
let imageData = UIImage.init(data: data!)!
//converting it into png data
let pngData = UIImagePNGRepresentation(imageData)
let mimeType = "image/png"
let fieldName = "files"
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = pngData{
multipartFormData.append(data, withName: fieldName, fileName: fileName, mimeType: mimeType)
}
}, usingThreshold: UInt64.init(), to: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition" , method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print("Succesfully uploaded")
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
}
}

Migrating from URLSession to Alamofire 4.3 in Swift 3, Encoding issue

What is the equivalent code of the following in Alamofire 4.3,Swift 3?
let baseUrl = "https://hiddenWebsite.com/api/index_load"
let url = URL(string: baseUrl)
let authObj = ["owner_id": "361900", "auth_key": "f408634ac1e14c08eebce46c34ab9db2", "device": "2", "version": "2.1.16"]
let infoObj = ["case": "feeds", "feeds_call_type": "init", "feed_type": "", "load_next_from": "1"]
let infoJSONData = try! JSONSerialization.data(withJSONObject: infoObj)
let infoStr = "info" + "=" + String(data: infoJSONData, encoding: String.Encoding.utf8)!
let authJSONData = try! JSONSerialization.data(withJSONObject: authObj)
let authStr = "auth" + "=" + String(data: authJSONData, encoding: String.Encoding.utf8)!
let combinedStr = infoStr + "&" + authStr
let reqdat = combinedStr.data(using: String.Encoding.utf8)
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = reqdat
let defaultSession = URLSession.shared
defaultSession.dataTask(
with: request,
completionHandler: { data, response, error in
guard error == nil else {
print("Error while fetching data: \(error)")
return
}
guard let data = data,
let json = try? JSONSerialization.jsonObject(
with: data,
options: JSONSerialization.ReadingOptions.mutableContainers)
else {
print("Nil data received")
return
}
print(json)
}).resume()
I'm currently migrating from Apple's URLSession to Alamofire, but stuck at this point. I think this has something to do with encodingParameter.
This is my failed attempt. I also tried with URLEncoding.httpbody but didn't work.
let baseUrl = "https://hiddenWebsite.com/api/index_load"
let masterParameter = [
"auth": ["owner_id": "361900",
"auth_key": "f408634ac1e14c08eebce46c34ab9db2",
"device": "2",
"version": "2.1.16"],
"info": ["case": "feeds",
"feeds_call_type": "init",
"feed_type": "",
"load_next_from": "1"]
]
Alamofire.request(baseUrl, method: .post, parameters: masterParameter, encoding: JSONEncoding.default).responseJSON { (response) in
print(response)
}
The working postman equivalent of this looks like
Postman Screenshot
The encoding you are using it not valid JSON. Therefore, you cannot use JSON.default as your encoding type because it will encode your masterParameter dictionary as a valid JSON dictionary.
Instead, you either need to build your URLRequest manually as you have done in your first example and use the Alamofire.request(urlRequest) API, or you can create your own ParameterEncoding where you pass your data into it then encode the URLRequest.
Thanks cnoon for answering. The following code solved the issue:
public enum JSONError: Error {
case serializing(String)
case encoding
}
extension String: ParameterEncoding {
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try urlRequest.asURLRequest()
request.httpBody = self.data(using: String.Encoding.utf8)
return request
}
}
let encodedStr = try getEncodedString(parameters: masterParameter)
Alamofire.request(baseUrl, method: .post, parameters: [:], encoding: encodedStr).responseJSON { response in
print(response)
}
where getEncodedString(parameters:) is defined as:
func getEncodedString(parameters: Parameters) throws -> String {
var encodedStr = ""
for (key, value) in parameters {
let jsonData: Data
do {
jsonData = try JSONSerialization.data(withJSONObject: value)
}
catch(let error) {
throw JSONError.serializing(error.localizedDescription)
}
guard let encodedJsonString = String(data: jsonData, encoding: .utf8) else {
throw JSONError.encoding
}
let keyValueStr = key + "=" + encodedJsonString
encodedStr += keyValueStr + "&"
}
if encodedStr.characters.last == "&" {
encodedStr.remove(at: encodedStr.index(before: encodedStr.endIndex))
}
return encodedStr
}