Google safe browsing returning 400 bad request - f#

Google is returning a 400 bad request; but what is wrong with the request?
open FSharp.Data
let apiKey = "key goes here - removed for stackoverflow"
let postUrl = "http://safebrowsing.clients.google.com/safebrowsing/downloads"
let testArray = "2\nhttp://www.google.com/\nhttp://ianfette.org/"
[<EntryPoint>]
let main argv =
let foo2 = Http.Request(postUrl, httpMethod = "Post",
query = [ "client", "api"; "apikey", apiKey; "appver", "1.0"; "pver", "2.2" ],
body = TextRequest (testArray)
)
0
I have verified that my key is correct by successfully executing get requests, it is only the post that is failing.

When I updated FSharp.Data to version 2.0.5 (released 2014-03-29) this started working. I can only assume that there was a bug in the previous version that is now fixed.
release notes state:
Added - to the list of default missing values. Re-added support for
specifying known HTTP headers in the wrong case. Fixed sending of HTTP
requests when using a portable class library version of FSharp.Data in
the full .NET version.
Here is the final (working) code:
open FSharp.Data
let apiKey = "key goes here"
let postUrl = "https://sb-ssl.google.com/safebrowsing/api/lookup"
let testArray = "2\nhttp://www.google.com/\nhttp://ianfette.org/"
[<EntryPoint>]
let main argv =
let foo2 = Http.Request(postUrl, httpMethod = "Post",
query = [ "client", "api"; "apikey", apiKey; "appver", "1.5.2"; "pver", "3.0" ],
body = TextRequest (testArray)
)
0
Thank you to Sergey Tihon for finding the error in my URL string in the question.

Related

Write to Google Sheets in Swift

I'm really confused how to write to an excel sheet, that is public. So far I have downloaded Alamofire and GoogleAPIClientForREST cocoapods. So I was wondering, if I want to write to the sheet do I first need to implement a google sign in or can I just send data over using Alamofire. I am super lost so If someone can help me that would be great.
Google sheet: https://docs.google.com/spreadsheets/d/1zJR0uk6Pb6BuxJihFyxwe4ipQdBY4E9FFR74geBj8p0/edit#gid=0
func makeAndSendRequest() {
let baseUrl = "https://sheets.googleapis.com/v4/spreadsheets"
let spreadsheetId = "1zJR0uk6Pb6BuxJihFyxwe4ipQdBY4E9FFR74geBj8p0"
let params = ["valueInputOption": "RAW"]
let range = "Studen!A3:B3"
//need to add params
let url = baseUrl + "/" + spreadsheetId + "/values/" + range + "/valueInputOption=RAW/"
let fullUrl = URL(string: url)!
//my values
let requestParams = [
"values": [
1,
2
]
]
//my auth is after Bearer so "Bearer 901390"
let header = ["Authorization":"Bearer "]
let requestURL = "https://sheets.googleapis.com/v4/spreadsheets/\(spreadsheetId)/values/\(range)?valueInputOption=RAW"
let req = Alamofire.request(requestURL, method: .put, parameters: requestParams, encoding: JSONEncoding.default,headers: header)
req.responseJSON { response in debugPrint(response) }
}
Try to fix this first.
valueInputOption is a query parameter, see: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update
You URL should at least be:
let url = baseUrl + "/" + spreadsheetId + "/values/" + range + "?valueInputOption=RAW"
next you need to fix your request body, range is required per document here: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update
{
"range": "A3:B3",
"values": [
[
1,
2
]
]
}
This range should be same as your range in your query parameter, say Sheet1!:A3:B3 as in your query parameter.
Note that it starts with the sheet name, it should not be "studen"
I have used the playground tool on the same page and able to call the api to change the data in your spreadsheet.
At the end I am getting 200 response code and following json:
{
"spreadsheetId": "1zJR0uk6Pb6BuxJihFyxwe4ipQdBY4E9FFR74geBj8p0",
"updatedRange": "Sheet1!A3:B3",
"updatedRows": 1,
"updatedColumns": 2,
"updatedCells": 2
}
----- Edit -----
As you asked, the API needs Oauth token, the framework to handle this is actually called G Suite
Please find the guide here:
https://developers.google.com/gsuite/guides/ios

I can't use twitter api with Nim

I want to use twitter api with Nim.
But, I can't solve error.
{"errors":[{"code":85,"message":"The list failed validation: A list's name can't be blank."}]}
I success authentication.
Which I make a mistake using twitter API or
using Nim library oauth1,
sending Post method body?
import tables, oauth1, strutils, httpclient, json
proc parseResponseBody(body: string): Table[string, string] =
let responses = body.split("&")
result = initTable[string, string]()
for res in responses:
let r = res.split("=")
result[r[0]] = r[1]
proc getRequestToken(consumerKey, consumerKeySecret: string): Table[string, string] =
let response = getOAuth1RequestToken(
"https://api.twitter.com/oauth/request_token",
consumerKey,
consumerKeySecret,
isIncludeVersionToHeader = true)
if response.status == "200 OK":
return parseResponseBody(response.body)
else:
assert(false, response.body)
proc getAccessToken(consumerKey, consumerKeySecret, requestToken, requestTokenSecret, verifier: string): Table[string, string] =
let response = getOAuth1AccessToken(
"https://api.twitter.com/oauth/access_token",
consumerKey,
consumerKeySecret,
requestToken,
requestTokenSecret,
verifier,
isIncludeVersionToHeader = true)
if response.status == "200 OK":
return parseResponseBody(response.body)
else:
assert(false, response.body)
let
consumerKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
consumerKeySecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
let requestToken = getRequestToken(consumerKey, consumerKeySecret)
echo getAuthorizeUrl("https://api.twitter.com/oauth/authorize", requestToken["oauth_token"])
let verifier = readLine(stdin)
let accessTokens = getAccessToken(
consumerKey,
consumerKeySecret,
requestToken["oauth_token"],
requestToken["oauth_token_secret"],
verifier)
let param = %*{"name": "chage","mode": "private","description": "description"}
let response = oauth1Request(
"https://api.twitter.com/1.1/lists/create.json",
consumerKey,
consumerKeySecret,
accessTokens["oauth_token"],
accessTokens["oauth_token_secret"],
httpMethod = HttpPost,
body = $param
)
echo response.body
Looking at the documentation for the Twitter API it seems like it takes it's input in the form of query parameters and not a JSON body. This means that you need to not create a param JSON object but rather a parameter string. This can be done by simple concatenation, but make sure to escape URI characters with something like: https://nim-lang.org/docs/uri.html#encodeUrl,string

Unable to encode String for URL in Swift 3

I used to develop iOS Apps using Objective-C. Now I have recently migrated to Swift. In my app, I have a button that opens MS Outlook App with the pre-filled Subject and Body.
I did a similar App in Objective-C and used the below code to Encode my String for URL.
NSString *emailSubject = #"Test Subject";
NSString *encodedSubject = [emailSubject stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
Now I am unable to do the same in Swift 3. Below is the code that I tried.
var subjectText: String = "Test Subject"
var encodedSubject = subjectText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
var stringURL: String = "ms-outlook://compose?subject=" + subjectText + "&body=TestingEmailNow"
// Convert the string to a URL.
var url = URL(string: stringURL)
// Open the app that responds to the URL scheme (should be Outlook).
UIApplication.shared.openURL(url!)
The error that I am getting is below.
fatal error: unexpectedly found nil while unwrapping an Optional value
2017-06-07 04:29:35.158030+0400 My App[1286:405793] fatal error: unexpectedly found nil while unwrapping an Optional value
I know that this error is coming due to the space in my Subject. I can say this because if I remove the space, I don't even have to encode it. It works directly. What am I doing wrong over here?
You made a simple mistake.
check your line
var stringURL: String = "ms-outlook://compose?subject=" + subjectText + "&body=TestingEmailNow"
you are using subjectText instead of encodedSubject
Complete code:
var subjectText: String = "Test Subject"
var encodedSubject = subjectText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
if let encodedSubject = encodedSubject {
var stringURL: String = "ms-outlook://compose?subject=" + encodedSubject + "&body=TestingEmailNow"
// Convert the string to a URL.
var url = URL(string: stringURL)
if let url = url {
// Open the app that responds to the URL scheme (should be Outlook).
UIApplication.shared.openURL(url)
}
}
Variable used was the problem but I'd also suggest using URLComponents instead of building the URL as string.
var subjectText: String = "Test Subject"
var components = URLComponents()
components.scheme = "ms-outlook"
components.host = "compose"
components.queryItems = [
URLQueryItem(name: "subject", value: subjectText),
URLQueryItem(name: "body", value: "TestingEmailNow")
]
if let url = components.url {
UIApplication.shared.openURL(url)
}

The '#' char gets converted to %23 causing the GET Request to fail

I am a new Swift developer using Swift 3 developing an iOS app. I need to make a URL Request to get some data from the web. That URL contains a # character.
I use URLComponents with URLQueryItems to build the request URL. During this process the # char gets converted to %23 which I think is valid utf8 encoding. Unfortunately, this causes the GET to fail.
To test I pasted the URL into my browser and changed %23 back to # and it worked just fine.
How can I fix this so it does not change # to URL. I did find a post from a couple years ago but it was using old framework items so it does not apply to me.
Below is the playground I made to illustrate and test this.
// ------------------------------------------------------------------
//: Playground - TestBuildURLWithParameters
//
// I am using this playground to build the proper
// URL for the GET request to get the detailed
// rtesults for a specific athlete where the "Key"
// is their Bib Nbr. If the GET cant find the specific
// Atlete with that URL it redirects you to the list
// of athlete results (which is no go to me in this case)
//
// Currently, there is a big "gotcha". In building the URL
// using component and query items, the foundation classes
// replace the '#' sign in the URL with the %23 which represents
// the pound sign. Unfortunately, the causes the GET to fail
// and redirects to athlete list which is not helpful
// I am still trying to figure out how to FORCE it to keep
// the '#" character in the URL so it will work
//
// ------------------------------------------------------------------
import Foundation
import UIKit
let baseURLString = "http://www.ironman.com/triathlon/events/americas/ironman-70.3/augusta/results.aspx"
let rd = "20150927"
let race = "augusta70.3"
let bibID = "93"
var detail = "1#axzz4FGGcjBOn"
print("Detail w/o unicocde: \(detail)")
detail = "1\u{0023}axzz4FGGcjBOn"
print("Detail with unicocde: \(detail)")
var components = URLComponents(string: baseURLString)!
var queryItems: [URLQueryItem] = [] // All Items after the "?"
let baseParams =
[
"rd": rd,
"race": race,
"bidID": bibID, // Note: HTML mispelled bib with bid so "bidID" is the URL search
"detail": detail
]
for (key, value) in baseParams
{
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
components.queryItems = queryItems // what does this look like
print("components: \(components)") // see it
It is not a good way to include fragment part of URL into query items.
Try this:
import Foundation
let baseURLString = "http://www.ironman.com/triathlon/events/americas/ironman-70.3/augusta/results.aspx"
let rd = "20150927"
let race = "augusta70.3"
let bibID = "93"
var detail = "1"
//# split the last query item and the fragment
let fragment = "axzz4FGGcjBOn"
var components = URLComponents(string: baseURLString)!
var queryItems: [URLQueryItem] = []
let baseParams =
[
"rd": rd,
"race": race,
"bidID": bibID,
"detail": detail
]
for (key, value) in baseParams
{
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
components.queryItems = queryItems
components.fragment = fragment
print("components: \(components)")
If you need you can choose the character that will receive the encoding.
In the charactersIn: you put all characters you want to encode.
Then you use the .inverted so all the others characters will go normal like this:
let customAllowedSet = NSCharacterSet(charactersIn:"=\"%/<>?#\\^`{|}").inverted
let encondedString = originalString.addingPercentEncoding(withAllowedCharacters: customAllowedSet)
print("enconded string: \(encondedString)")
Encode your parameters and then add it to URL, this will encode # before hitting API and you'll get desired result.
To encode parameters, you can use below code.
var parameterString = "your parameter string"
var encodedString = parameterString .addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(encodedString !)
I did get an answer via email from a friend that works for now. Basically, I added the query items manually to the URL using the URL extension below so it didn't monkey with the '#' char:
extension URL {
func appendingNonEscapedQueryItems(_ queryItems: [URLQueryItem]) -> URL {
let url = self
var urlString = url.absoluteString
for queryItem in queryItems {
let queryName = queryItem.name
guard let queryValue = queryItem.value else {
continue
}
let query = queryName + "=" + queryValue
if queryItem == queryItems.first {
urlString = urlString + "?" + query
}
else
{
urlString = urlString + "&" + query
}
}
return URL(string: urlString)!
}
}
...
let requestURL = components.url!.appendingNonEscapedQueryItems(queryItems)
print("URL \(requestURL)")

How to send litter '&' as url parameter - swift

I have a code to update name of department in the database .. I use this encoding code :
let myurlstring="http:example/updateDepartment.php?deptName="+"\(deptName)"+"&id="+"\(deptID)"
let escapedString = myurlstring.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
let myUrl = URL(string:escapedString!)!
It works very well , but when deptName string contains this litter & it's not working.
example1 : send request with deptName = "CIT and Network" it will work .
example2 : send request with deptName = "CIT & Network" will be in the database as only "CIT" any litter after & will be skipped.
any help ?
Use URLComponents + URLQueryItem instead. It can be used to encode the query part from structured input:
var comp = URLComponents(string: "http://example.com")!
comp.path = "/some path to/update.php"
comp.queryItems = [
URLQueryItem(name: "deptName", value: "CIT & Network"),
URLQueryItem(name: "id", value: "123456"),
]
let url = comp.url!
print(url)
// http://example.com/some%20path%20to/update.php?deptName=CIT%20%26%20Network&id=123456

Resources