I am trying to shorten several thousands of URLs using Google API. I am using httr to do POST. Whenever I provide a URL to post as a variable I get "Client error: (400) Bad Request" but when the same URL is provides directly as string (for example "http://www.google.com") everything works fine. A minimal example is provided below:
library(httr)
library(httpuv)
# enter data
mydata <- data.frame(Link = "http://www.google.com")
# 1. Find OAuth settings for google:
# https://developers.google.com/accounts/docs/OAuth2InstalledApp
oauth_endpoints("google")
# 2. Register an application at https://cloud.google.com/console#/project
myapp <- oauth_app("google", key = "key goes here", secret = "secret goes here")
# 3. Get OAuth credentials
google_token <- oauth2.0_token(oauth_endpoints("google"), myapp, scope = "https://www.googleapis.com/auth/urlshortener")
This returns Error: client error: (400) Bad Request
req <- POST('https://www.googleapis.com/urlshortener/v1/url?fields=id',
add_headers("Content-Type"="application/json"),
body='{"longUrl": mydata$Link[1]}', config(token = google_token))
stop_for_status(req)
This works just fine
req <- POST('https://www.googleapis.com/urlshortener/v1/url?fields=id',
add_headers("Content-Type"="application/json"),
body='{"longUrl": "http://www.google.com"}', config(token = google_token))
stop_for_status(req)
I tried encoding URLs, testing both http and https and but none of the above seem to have any effect. Could anyone provide me with any suggestions? Thank you in advance!
-jacek
You have a couple of problems.
First: data frames coerce character vectors to factors:
mydata <- data.frame(link = "http://www.google.com")
class(mydata$link)
#> [1] "factor"
mydata <- data.frame(link = "http://www.google.com", stringsAsFactors = FALSE)
class(mydata$link)
#> [1] "character"
Second, you're sending '{"longUrl": mydata$Link[1]}'
to google - i.e.
the longUrl you are submitting is mydata$Link[1]
, not
http://www.google.com
. It's easiest to fix that by using jsonlite
to
do the encoding:
req <- POST('https://www.googleapis.com/urlshortener/v1/url?fields=id',
body = list(longUrl = jsonlite::unbox(mydata$link[1]),
encode = "json",
config(token = google_token)
)
stop_for_status(req)
(Unfortunately the unbox()
is necessary because jsonlite defaults to
converting length-1 vetors into js arrays, not scalars.)