Ximilar POST request with image URL and headers - swift

I am trying to run a post request to send an image to the ximilar app. Not even sure if my request is 100% correct. Each time I get the same response of:
https://api.ximilar.com/recognition/v2/classify/ } { Status Code: 400, Headers {
"Content-Type" = (
"application/json"
);
Date = (
"Mon, 12 Apr 2021 04:02:58 GMT"
);
Server = (
"nginx/1.16.1"
);
"Strict-Transport-Security" = (
"max-age=31536000"
);
Vary = (
"Accept, Origin"
);
allow = (
"POST, OPTIONS"
);
"referrer-policy" = (
"same-origin"
);
"x-content-type-options" = (
nosniff
);
"x-frame-options" = (
DENY
);
} }
{
records = (
"Expected a list of items but got type \"str\"."
);
}
My code: (not sure if the body values are written right.)
let url = URL(string: "https://api.ximilar.com/recognition/v2/classify/")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Token __MyTOKEN__", forHTTPHeaderField: "Authorization")
let body = [
"task_id" : "c03c288b-a249-4b17-9f63-974c2f30beb9",
"records" : "https://www.sticky.digital/wp-content/uploads/2013/11/img-6.jpg"
]
let bodyData = try? JSONSerialization.data(withJSONObject: body, options: [] )
request.httpMethod = "POST"
request.httpBody = bodyData
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
I want to be able to output the JSON response in the console.
Here is the code in curl which works fine:
curl -H "Content-Type: application/json" -H "authorization: Token __API_TOKEN__" https://api.vize.ai/v2/classify -d '{"task_id": "0a8c8186-aee8-47c8-9eaf-348103feb14d", "version": 2, "descriptor": 0, "records": [ {"_url": "__IMAGE URL HERE__" } ] }'

The server is reporting an error for records:
Expected a list of items but got type "str"
It is saying that it was expecting an array of items for records, but only received a string. In your curl, records is an array of dictionaries with a single key, _url, but in Swift the value is just a string, consistent with what the error reported. You also supply version and descriptor in curl, but not in the Swift example.
Thus, you might try:
let body: [String: Any] = [
"task_id" : "c03c288b-a249-4b17-9f63-974c2f30beb9",
"version": 2,
"descriptor": 0,
"records" : [
[
"_url": "https://www.sticky.digital/wp-content/uploads/2013/11/img-6.jpg"
]
]
]
Alternatively, you might define Encodable types as outlined in Encoding and Decoding Custom Types:
struct XimilarRequest: Encodable {
let taskId: String
let version: Int
let descriptor: Int
let records: [XimilarRecord]
}
struct XimilarRecord: Encodable {
let url: URL
enum CodingKeys: String, CodingKey {
case url = "_url"
}
}
Then you can do:
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let imageUrl = URL(string: "https://www.sticky.digital/wp-content/uploads/2013/11/img-6.jpg")!
let ximilarRequest = XimilarRequest(
taskId: "c03c288b-a249-4b17-9f63-974c2f30beb9",
version: 2,
descriptor: 0,
records: [XimilarRecord(url: imageUrl)]
)
request.httpBody = try encoder.encode(ximilarRequest)

Hi here is the example that should work for you (fill the Auth token and _url of the image):
import Foundation
let headers = [ "Content-Type": "application/json", "authorization": "Token __API_TOKEN__" ] let parameters = [ "task_id": "0a8c8186-aee8-47c8-9eaf-348103feb14d", "version": 2, "records": [["_url": "__IMAGE URL HERE__"]] ] as [String : Any]
let postData = JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "https://api.ximilar.com/recognition/v2/classify")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data
let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) {
print(error) } else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse) } })
dataTask.resume()

Related

Convert Firebase Firestore API POST request from CURL to Swift URLRequest

I have a simple cURL request which inserts data into Firestore database. This works, and no authentication is needed. I need to use cURL as no Firestore library is available for watchOS.
curl -X POST -H "Content-Type: application/json" -d '
{
"fields": {
"Field1": {
"stringValue": "'"$var12"'"
},
"Field2": {
"stringValue": "'"$var22"'"
},
"Field3": {
"stringValue": "$var32"
}
}
}' "https://firestore.googleapis.com/v1/projects/project-a9c7/databases/(default)/documents/TestRuns/3001/MyRuns"
However, when I try to rewrite the request using URLRequest to use it in watchOS SwiftUI App, the app returns an error.
The previous answer did not help me.
ERROR:
The code is 404 not found, but the same URL works from terminal.
statusCode should be 2xx, but is 404
response = <NSHTTPURLResponse: 0x6000021482c0> { URL: https://firestore.googleapis.com/v1/projects/runny-a9c7/databases/(default)/documents/TestRuns/3001/MyRuns } { Status Code: 404, Headers {
"Alt-Svc" = ( ...
If I use PATCH instead of PUT as suggested, the response is 400, and the code still doesn't create new record in database.
The URLRequest call, which I tried running from SwiftUI Playground and also watchOS App:
import Foundation
// CREDIT: https://stackoverflow.com/questions/63530589/using-post-and-auth-with-firebase-database-and-swift
extension Dictionary {
func percentEncoded() -> Data? {
return map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
func percentEncodedString() -> String? {
return map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
}
}
class Body: Codable {
var name: String
init(name: String){
self.name = name
}
}
extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]#" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}
let url = "https://firestore.googleapis.com/v1/projects/runny-a9c7/databases/(default)/documents/TestRuns/3001/MyRuns"
var request = URLRequest(url: URL(string: url)!)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "PUT"
let parameters: [String: Any] = [
"field1": "A",
"field2": "B"
]
request.httpBody = parameters.percentEncoded()
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil else { // check for fundamental networking error
print("App error", error ?? "Unknown error")
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
task.resume()
Do you have any idea, when went wrong here, and how to fix the problem?
Thanks for any help.
I needed to use the POST method:
request.httpMethod = "POST"
Then , I adjusted the parameters:
let parameters: [String:[String:[String: String]]] = [
"fields": ["Field1": ["stringValue": "val"]]
]
Finally, I sent the JSON data using the JSONSerialization class.
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
The data got successfully written to Firestore database.
Thanks so much Larme!.

Get "Parse Error" when sending request to YouTube Data API to start a resumable upload session

https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
I try to follow this guide to start a resumable session.
But server returns this response :
success({
error = {
code = 400;
errors = (
{
domain = global;
message = "Parse Error";
reason = parseError;
}
);
message = "Parse Error";
};
})
Swift 5/ Alamofire 5
let filePath = "/Users/lucas/Documents/test.mp4"
do{
let attr = try FileManager.default.attributesOfItem(atPath: filePath)
let dict = attr as NSDictionary
let fileSize = dict.fileSize()
let dicSnippest = ["title": "TestVideo",
"description": "_description_",
"tags":"gundam",
"catagoryId":"22"]
let dicStatus = ["privacyStatus": "private",
"embedded": "True",
"license": "youtube"]
let sessionParam = ["snippet": dicSnippest,
"status": dicStatus
]
let targetUrl = "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status"
let sessionHeaders = HTTPHeaders([
"Authorization": "Bearer \(token)",
"Content-Type": "application/json; charset=utf-8",
"Content-Length": "\(fileSize)",
"X-Upload-Content-Length": "\(fileSize)",
"X-Upload-Content-Type": "application/octet-stream"])
print("token: \(token)")
print("\(filePath): \(fileSize) bytes")
AF.request(targetUrl, method: .post, parameters: sessionParam, encoding: URLEncoding.default, headers: sessionHeaders).responseJSON {
response in
print("Http Status Code: \(String(describing: response.response?.statusCode))")
switch (response.result)
{
case .success(_):
print("Get Server Response!!")
print(response.result)
break
case .failure(let error):
print("Failure!!")
print(error)
break
}
}
} catch {
}
BTW, I modify the parameter of AF.request - encoding from URLEncoding.httpBody to JSONEncoding.default.
This error is happened:
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)

Upload file to mailgun server with swift

I am trying to attach file to Mailgun. Here is my curl command:
curl -s --user 'api:key-XXX'
https://api.mailgun.net/v3/sandbox---.mailgun.org/messages
-F from='Excited User<mailgun#sandbox---.mailgun.org>'
-F to=mail#gmail.com
-F subject='Hello'
-F text='Testing some Mailgun awesomness!'
-F attachment='#/Users/.../mytestfile.jpeg'
Result: Ok, the file has been attached to the message and been successfully transferred.
After that, I tried doing it with URLRequest:
guard let filePath = Bundle.main.url(forResource: "domru", withExtension: "jpeg") else {
print(">>>can't find path")
return
}
let parameters: HTTPHeaders = [
"from": "Excited User<mailgun#sandbox---.mailgun.org>",
"to": "mail#gmail.com",
"subject": "hello",
"text": "my text message" ]
let data = encodeRequest(parameters: parameters, attachment: filePath)
var request = URLRequest(url: URL(string:"https://api.mailgun.net/v3/sandbox---.mailgun.org/messages")!)
request.httpMethod = "POST"
request.httpBody = data.data(using: .utf8)
request.addValue("Basic \(credentialData!)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request, completionHandler:{(data, response, error) in
if let err = error {
print(err)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
private func encodeRequest(parameters:[String:String], attachment: URL) -> String {
var result = ""
for (key, value) in parameters {
result.append("\(key)="+"\(value)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! + "&")
}
result.append("attachment="+attachment.path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)
return result
}
Result: The text of the message has been delivered, but the file has not been attached.
I also tried to solve that with Alamofire:
let imageData = UIImageJPEGRepresentation(UIImage(named:"domru.jpeg")!, 1)
let header : HTTPHeaders = ["Authorization":"Basic \(credentialData!)"]
Alamofire.upload(
// parameters are the same as in the previous part of code
multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key)
}
multipartFormData.append(imageData!, withName: "domru", fileName: "domru.jpeg", mimeType: "image/jpeg")
},
to: "https://api.mailgun.net/v3/sandbox---.mailgun.org/messages",
method: .post,
headers: header,
encodingCompletion: { (result) in
debugPrint(result)
}
Result the same: The attachment has not been attached to the message.
How attach a file to a message in this case?
For anyone still working on this. It seems that the MailGun API looks for the name to be attachment on each of the attachments included so this line:
multipartFormData.append(imageData!, withName: "domru", fileName: "domru.jpeg", mimeType: "image/jpeg")
would need to be changed to:
multipartFormData.append(imageData!, withName: "attachment", fileName: "domru.jpeg", mimeType: "image/jpeg")
not sure if that entirely fixes it

How to write GraphQL Query

I have a working web graphql query as :
{
me{
... on Student{
profile {
fullName
emailId
mobileNumber
civilId
address
city
state
country
zipCode
userProfilePic
userCategory
createdAt
updatedAt
}
}
}
}
It returns the profile details of a particular student. I log using mutation and gets the token for a user.
I want to create a graphql file (ex. StudentProfile.graphql) in order to make fetch request (similar to http. get) using Apollo client.
I make this request to fetch the graphql query.
func fetchStudentProfileDetails(){
let tokenString = "Bearer " + "....my token ..."
print(tokenString)
let newApollo: ApolloClient = {
let configuration = URLSessionConfiguration.default
// Add additional headers as needed
configuration.httpAdditionalHeaders = ["Authorization": tokenString]
let url = URL(string: "http://52.88.217.19/graphql")!
return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))
}()
newApollo.fetch(query: StudentProfileQuery()) { (result, error) in
self.profileDetailsTextView.text = "Success"
if let error = error {
NSLog("Error while fetching query: \(error.localizedDescription)");
self.profileDetailsTextView.text = error.localizedDescription
}
guard let result = result else {
NSLog("No query result");
self.profileDetailsTextView.text = "No query result"
return
}
if let errors = result.errors {
NSLog("Errors in query result: \(errors)")
self.profileDetailsTextView.text = String(describing: errors)
}
guard let data = result.data else {
NSLog("No query result data");
return
}
}
}
How do I convert the following web query into a query in the .graphql file?
so, you can call to create new document into Graphql server using a simple NSUrlSession
let headers = ["content-type": "application/json"]
let parameters = ["query": "mutation { createProfile(fullName: \"test name\" emailId: \"test#email.com\") { id } }"] as [String : Any]
let postData = JSONSerialization.data(withJSONObject: parameters, options: [])
let request = NSMutableURLRequest(url: NSURL(string: "https://<url graphql>")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
I'm not sure I completely understand your question, but you should be able to use HTTP to make queries. For most people, a *.gql file just contains the query as a String which they URLEncode. Below is an example of reading from a variable but you could do just the same reading the query from a file as a string/buffer.
const myQuery = `{
user {
name
}
}`;
const queryURL = "http://52.88.217.19/graphql/?query=" + URLEncode(myQuery);
fetch(queryURL)
.then((result) => {
console.log(result);
})
If this does not answer your question, please help me better understand what you are asking, and I will try to revise my answer.

Swift 3, Alamofire json get "error = "Invalid API key/secret pair.""

I get - error = "Invalid API key/secret pair.";
When I try a POST request in REST client in chrome:
I get the correct json information:
But in Swift with Alamofire I try to do the same request and get an error...
My code:
func getRawJSON(method: String) {
let publicKey = "YF9RCYRE-GL29DI0T-8GE62O2X-9OQ21A2P"
let secretKey = "79aef0ae2bb54df5c5a4e6c28757ddf54a184964fb8c978b5770895944ca7778b582ff390dffdf073a77aac1de1ea1a793dfa6629c3394465345d31a62f953e9"
let APIURL = "https://www.poloniex.com/tradingApi"
let timeNowInt = Int(NSDate().timeIntervalSince1970)
let timeNow = String(timeNowInt)
let query = NSURLComponents()
query.queryItems = [NSURLQueryItem(name: "command", value: method) as URLQueryItem,
NSURLQueryItem(name: "nonce", value: timeNow) as URLQueryItem]
let requestString = query.query!
let params = [
"command": method,
"nonce:": timeNowInt
] as [String : Any]
let codering = requestString.hmac(algorithm: .SHA512, key: secretKey)
let headers = [
"Sign": codering,
"Key": publicKey,
"Content-Type":"application/x-www-form-urlencoded"] as [String : String]
print(headers)
Alamofire.request(APIURL, withMethod: .post, parameters: params, encoding: .url, headers: headers)
.responseJSON { response in
print(response)
}
}