upload image from xcode project (swift) to webapi - swift

I'm building a scan app for iphone (xcode, swiftui), but I'm struggeling to upload the images to my webapi (.net), which communicates with a WCF service. I can easily send scanned barcodes, but the images send have the correct name, but are 0 bytes empty. What could be wrong here??
This is my sendcode in swift:
func send_photo (sessionid: String, image: UIImage) {
let req = NSMutableURLRequest(url: NSURL(string: ".../save_photo")! as URL)
let ses = URLSession.shared
req.httpMethod = "POST"
req.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
req.setValue(sessionid, forHTTPHeaderField: "X-FileName")
let jpgData = image.jpegData(compressionQuality: 1.0)
req.httpBodyStream = InputStream(data: jpgData!)
let task = ses.uploadTask(withStreamedRequest: req as URLRequest)
task.resume()
}
This is the webapi controller code:
[System.Web.Http.Route(".../save_photo")]
public string Post([FromBody] Stream _photo)
{
var sessionid = "";
using (var client = new service.Service1Client())
{
client.ClientCredentials.UserName.UserName = "....";
client.ClientCredentials.UserName.Password = ".....";
sessionid = Request.Headers.GetValues("X-FileName").First();
return client.Save_photo(new service.photo {sessionid= sessionid, image = _photo});
}
}
and this is de code in the WCF service:
public string Save_photo(photo _photo)
{
try
{
var fileStream = new FileStream(#"...\PHOTO\" + _photo.sessionid + "_" + DateTime.Now.ToString("yyyyMMdd_hhmmss") + ".jpg", FileMode.Create, FileAccess.Write);
_photo.image.Position = 0;
_photo.image.CopyTo(fileStream);
}
catch
{
return "nok";
}
return "ok";
}
Why does the resulting image could be empty??
Thanks for the suggestions.

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!.

How to emit an custom event in socket.io?

this is the first time I work with socket. I'm creating a chat feature that connect from my app to the server. I tried a couple ways but nothing works. I connect my app with socket/ Websocket successfully but I emit but not getting return data from server.
let SocketURL:String = "https://apps.abc.com:8080"
let WSSSocketURL:String = "wss://apps.abc.com:8080"
var conversationID:Int = 0
var socket:SocketIOClient?
var socketManager:SocketManager?
var otherChatUser:ChatUser = ChatUser()
var messageList:[ChatMessage] = [ChatMessage]()
var NumberOfSection:Int = 2
func setupSocket() -> Void {
socketManager = SocketManager(socketURL: URL(string: SocketURL)!, config: [.log(true), .compress])
self.socket = socketManager?.defaultSocket
socketManager?.config = SocketIOClientConfiguration(
arrayLiteral: .connectParams(["token": KeychainService.getWssToken() as Any, "EIO" : 3]),
.path("/wss"))
self.socket!.connect()
self.socket?.on(clientEvent: .connect) {
data, ack in
self.con_create()
}
}
func con_create() -> Void {
self.socketManager?.engine?.ws?.connect()
self.socketManager?.engine?.ws?.onConnect = {
let JsonData = [ "user" : self.otherChatUser.AuthID ]
self.socket?.emit("con_create", JsonData)
// expect to get back the conversation ID from the server after socket.on
self.socket?.on("con_create") {
(data, ack) in
print("con_create")
let json = data[1] as? JSON
self.conversationID = json!["id"].intValue
}
}
}
self.conversationID should be a whole number like 16 or 15.

Marvel API 409 response, "You must provide a user key"

Wondering if anyone can help me here:
private static func getURLRequestData(completion: #escaping (Data?) -> ()) {
// Gets the raw JSON Data
let session = URLSession(configuration: .default)
guard let url = URL(string: urlString) else { return }
var urlRequest = URLRequest(url: url)
let headers = [
"ts" : ts,
"apikey" : apiKey,
"hash" : hash,
"limit" : limit,
"orderBy" : orderedBy
]
urlRequest.allHTTPHeaderFields = headers
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print(#line, error!.localizedDescription)
}
print(response)
completion(data)
}
task.resume()
}
As you can see, I am setting the headers correctly with my API Key but for some reason I'm getting a 409 return which is a missing "user key".
Has anyone experienced anything like this. For what its worth, the exact same request is working in Paw
You must provide informations according documentation link documentation here
Example:
var publickey = 'you-public-key';
var privatekey = 'you-private-key';
var ts = new Date().getTime();
var stringToHash = ts + privatekey + publickey;
var hash = md5(stringToHash);
var baseUrl = 'https://gateway.marvel.com:443/v1/public/characters';
var limit = 20;
var url = baseUrl + '?limit=' + limit + '&ts=' + ts + '&apikey=' + publickey + '&hash=' + hash;

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.

Can someone find the error and verify my Swift NSURLSession code?

I am writing my first, basic IOS app using Swift that will poll a Proliphix IP Thermostat and display the temperature. I have converted an HTTP Post to NSURLSession using Paw, but the converted code appears to have a 3 syntax errors when I load it in Xcode Playground.
My goal right now is to get this working in Playground, but ultimately use it in my App code. Could someone please load this code in your own Xcode Playground and fix the error and make it work? The URL is a public IP address of the thermostat and If working correctly, it will poll the thermostat and return a value for OID4.3.2.3 and = something like 772& (currently 77.2 degrees).
class MyRequestController {
func sendRequest() {
/* Configure session, choose between:
* defaultSessionConfiguration
* ephemeralSessionConfiguration
* backgroundSessionConfigurationWithIdentifier:
And set session-wide properties, such as: HTTPAdditionalHeaders,
HTTPCookieAcceptPolicy, requestCachePolicy or timeoutIntervalForRequest.
*/
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
/* Create session, and optionally set a NSURLSessionDelegate. */
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
/* Create the Request:
My API (POST http://my-thermostat.dyndns.org:8083/get)
*/
var URL = NSURL(string: "http://my-thermostat.dyndns.org:8083/get")
let request = NSMutableURLRequest(URL: URL!)
request.HTTPMethod = "POST"
// Headers
request.addValue("Basic dXNlcjpwYXNzd29yZA==", forHTTPHeaderField: "Authorization")
// Form URL-Encoded Body
let bodyParameters = [
"OID4.3.2.3": "",
]
let bodyString = self.stringFromQueryParameters(bodyParameters)
request.HTTPBody = bodyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
/* Start a new Task */
let task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if (error == nil) {
// Success
let statusCode = (response as NSHTTPURLResponse).statusCode
println("URL Session Task Succeeded: HTTP \(statusCode)")
}
else {
// Failure
println("URL Session Task Failed: %#", error.localizedDescription);
}
})
task.resume()
}
/**
This creates a new query parameters string from the given NSDictionary. For
example, if the input is #{#"day":#"Tuesday", #"month":#"January"}, the output
string will be #"day=Tuesday&month=January".
#param queryParameters The input dictionary.
#return The created parameters string.
*/
func stringFromQueryParameters(queryParameters : Dictionary<String, String>) -> String {
var parts: [String] = []
for (name, value) in queryParameters {
var part = NSString(format: "%#=%#",
name.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!,
value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
parts.append(part)
}
return "&".join(parts)
}
/**
Creates a new URL by adding the given query parameters.
#param URL The input URL.
#param queryParameters The query parameter dictionary to add.
#return A new NSURL.
*/
func NSURLByAppendingQueryParameters(URL : NSURL!, queryParameters : Dictionary<String, String>) -> NSURL {
let URLString : NSString = NSString(format: "%#?%#", URL.absoluteString!, self.stringFromQueryParameters(queryParameters))
return NSURL(string: URLString)!
}
}
I assume I need the following above this code in Playground to work properly?
import Foundation
import XCPlayground
Last, the HTTP Post I used to convert was from the following and Paw converted this to NSURLSession above.
POST /get HTTP/1.1
Authorization: Basic dXNlcjpwYXNzd29yZA==
Content-Type: application/x-www-form-urlencoded
Host: my-thermostat.dyndns.org:8083
Connection: close
User-Agent: Paw/2.2.2 (Macintosh; OS X/10.10.4) GCDHTTPRequest
Content-Length: 11
OID4.3.2.3=
Thank you for your help!
If I create a playground with your code I get three errors.
One in the function sendRequest() where you must change this line:
let statusCode = (response as NSHTTPURLResponse).statusCode
to
let statusCode = (response as! NSHTTPURLResponse).statusCode
(as! instead of as)
One in the function stringFromQueryParameters where you must change the following line
parts.append(part)
to
parts.append(part as String)
(add as String)
And one in the function NSURLByAppendingQueryParameters where you must change this:
return NSURL(string: URLString)!
to this:
return NSURL(string: URLString as String)!
(add as String)
And then the compiler seems satisfied...at least on my machine :-)
And yes, you need to import Foundation and XCPlayground as you figured out already.
Furthermore, if you need to make asynchronous calls...as is the case here, you'll need this method in the top of your code:
XCPSetExecutionShouldContinueIndefinitely()
(you can read more about it here)
And finally, to actually see your code run, you can add this to the bottom of your code, after the class definition:
let requestController = MyRequestController()
requestController.sendRequest()
Here is the complete code
import Foundation
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely()
class MyRequestController {
func sendRequest() {
/* Configure session, choose between:
* defaultSessionConfiguration
* ephemeralSessionConfiguration
* backgroundSessionConfigurationWithIdentifier:
And set session-wide properties, such as: HTTPAdditionalHeaders,
HTTPCookieAcceptPolicy, requestCachePolicy or timeoutIntervalForRequest.
*/
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
/* Create session, and optionally set a NSURLSessionDelegate. */
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
/* Create the Request:
My API (POST http://my-thermostat.dyndns.org:8083/get)
*/
var URL = NSURL(string: "http://my-thermostat.dyndns.org:8083/get")
let request = NSMutableURLRequest(URL: URL!)
request.HTTPMethod = "POST"
// Headers
request.addValue("Basic dXNlcjpwYXNzd29yZA==", forHTTPHeaderField: "Authorization")
// Form URL-Encoded Body
let bodyParameters = [
"OID4.3.2.3": "",
]
let bodyString = self.stringFromQueryParameters(bodyParameters)
request.HTTPBody = bodyString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
/* Start a new Task */
let task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if (error == nil) {
// Success
let statusCode = (response as! NSHTTPURLResponse).statusCode
println("URL Session Task Succeeded: HTTP \(statusCode)")
}
else {
// Failure
println("URL Session Task Failed: %#", error.localizedDescription);
}
})
task.resume()
}
/**
This creates a new query parameters string from the given NSDictionary. For
example, if the input is #{#"day":#"Tuesday", #"month":#"January"}, the output
string will be #"day=Tuesday&month=January".
#param queryParameters The input dictionary.
#return The created parameters string.
*/
func stringFromQueryParameters(queryParameters : Dictionary<String, String>) -> String {
var parts: [String] = []
for (name, value) in queryParameters {
var part = NSString(format: "%#=%#",
name.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!,
value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
parts.append(part as String)
}
return "&".join(parts)
}
/**
Creates a new URL by adding the given query parameters.
#param URL The input URL.
#param queryParameters The query parameter dictionary to add.
#return A new NSURL.
*/
func NSURLByAppendingQueryParameters(URL : NSURL!, queryParameters : Dictionary<String, String>) -> NSURL {
let URLString : NSString = NSString(format: "%#?%#", URL.absoluteString!, self.stringFromQueryParameters(queryParameters))
return NSURL(string: URLString as String)!
}
}
let requestController = MyRequestController()
requestController.sendRequest()
Hope this helps