Trying to access google places using google api client in GAE - google-app-engine

I am trying to access google places api from appengine using code like this:
String PLACES_DETAILS_URL = "https://maps.googleapis.com/maps/api/place/details/json";
// setup up the HTTP transport
HttpTransport transport = new UrlFetchTransport();
// add default headers
GoogleHeaders defaultHeaders = new GoogleHeaders();
transport.defaultHeaders = defaultHeaders;
transport.defaultHeaders.put("Content-Type", "application/json");
JsonHttpParser parser = new JsonHttpParser();
parser.jsonFactory = new JacksonFactory();
transport.addParser(parser);
// build the HTTP GET request and URL
HttpRequest request = transport.buildGetRequest();
request.setUrl(PLACES_DETAILS_URL);
GenericData data = new GenericData();
data.put("reference", restaurantGoogleId);
data.put("sensor", "false");
data.put("key", ApplicationConstants.GoogleApiKey);
JsonHttpContent content = new JsonHttpContent();
content.jsonFactory=new JacksonFactory();
content.data = data;
request.content = content;
try {
HttpResponse response = request.execute();
String r = response.parseAsString();
r=r;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I don't know even if this is the recommended way. If so, why this doesn't work?If I put a request in the browser directly it works, but with this code it always returns me "Request Denied".
Thanks in advance.

At the end it was easy, I mixed get and post verbs:
HttpTransport transport = new UrlFetchTransport();
// add default headers
GoogleHeaders defaultHeaders = new GoogleHeaders();
transport.defaultHeaders = defaultHeaders;
transport.defaultHeaders.put("Content-Type", "application/json");
JsonCParser parser = new JsonCParser();
parser.jsonFactory = new JacksonFactory();
transport.addParser(parser);
// build the HTTP GET request and URL
HttpRequest request = transport.buildGetRequest();
request.setUrl("https://maps.googleapis.com/maps/api/place/details/json?reference=CmRYAAAAciqGsTRX1mXRvuXSH2ErwW-jCINE1aLiwP64MCWDN5vkXvXoQGPKldMfmdGyqWSpm7BEYCgDm-iv7Kc2PF7QA7brMAwBbAcqMr5i1f4PwTpaovIZjysCEZTry8Ez30wpEhCNCXpynextCld2EBsDkRKsGhSLayuRyFsex6JA6NPh9dyupoTH3g&sensor=true&key=<APIKEY>");
try {
HttpResponse response = request.execute();
String r = response.parseAsString();

Related

Proper way to post to a servlet on Google App Engine from a Java client application

I have deployed an to App Engine. I setup SSL, and associated it with a custom domain. When I was developing the app locally, sending to a servlet via http://localhost:8080/servlet, worked as expected, but when I deploy it to App Engine, I have yet to get the appropriate result. I've tried many things, and the response codes I keep getting are either 404 or 500.
I startied with a simple HTTPUrlConnection and DataOutputstream to send a JSON to the servlet, and get an appropriate response. Like so:
URL url;
HttpURLConnection connection = null;
try {
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("custom-Header", "XYZ");
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(urlParameters);
wr.flush ();
wr.close ();
//Get Response
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
}
finally {
if(connection != null) {
connection.disconnect();
}
}
This works locally.
I've now tried Apache Common's HttpAsyncClient, to check if it maybe a timing issue:
final ResponseObject responseObject = new ResponseObject(); //my simple POJO
try(CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
.setSSLStrategy(sslSessionStrategy)
.build()) {
httpclient.start();
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json");
post.setHeader("custom-Header", "XYZ");
post.setHeader("Content-Language", "en-US");
HttpEntity entity = new ByteArrayEntity(urlParameters);
post.setEntity(entity);
final CountDownLatch latch1 = new CountDownLatch(1);
httpclient.execute(post, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response) {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
try {
responseObject.message = entity != null ? EntityUtils.toString(entity) : null;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
responseObject.exception = new ClientProtocolException("Unexpected response status: " + status);
}
latch1.countDown();
}
public void failed(final Exception ex) {
responseObject.exception = ex;
latch1.countDown();
}
public void cancelled() {
latch1.countDown();
}
});
latch1.await();
if(responseObject.exception != null) {
throw responseObject.exception;
} else {
return responseObject.message;
}
}
This also works locally, but when trying to reach AppEngine, still no go.
Here's my simple web.xml:
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>my.servlet.package.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>everything</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
</welcome-file-list>
Locally, I post to http://localhost:8080/login. As for App Engine, I posted to the ff:
https://myapp.appspot.com/login
https://myapp.customdomain.com/login
I've tried changing up the url-pattern. I started with /login, then did login, then explicitly tried the both App Engine and custom domain urls (i.e. myapp.appspot.com/login and myapp.mydomain.com/login). I also tried having an actual jsp or html page to post to, after trying not having an actual page associated with the servlet i.e. login.jsp or login.html.
When I used HttpAsyncClient (my choice due to SSLContext), the best result I got was the HTML of the page associated with the servlet, but never the response I need from the Servlet.
Any ideas?
Found the answer on one of Google Cloud Platform's scattered docs:
https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled
https://cloud.google.com/appengine/docs/standard/java/how-requests-are-routed
Basically, you'll have to prepend your project's appspot url e.g. myapp.appspot.com, with the version ID of any actively serving instance of your app. You can find such IDs under the Versions page of your App Engine console. For example: https://versionId.myapp.appspot.com.

Send a PDF as an attachment through Sendgrid

I'm using Sendgrid to send emails through an app on GAE. It's working fine, but I also want to be able to send PDFs as an attachment.
I'm not using Sendgrid.jar file in my project. I've just used Sendgrid.java. And this class has no methods by which i can add attachments. Can someone help me?
public static boolean sendEmail(String fromMail, String title, String toMail, String message) throws IOException {
Email from = new Email(fromMail);
String subject = title;
Email to = new Email(toMail);
Content content = new Content("text/html", message);
Mail mail = new Mail(from, subject, to, content);
Path file = Paths.get("file path");
Attachments attachments = new Attachments();
attachments.setFilename(file.getFileName().toString());
attachments.setType("application/pdf");
attachments.setDisposition("attachment");
byte[] attachmentContentBytes = Files.readAllBytes(file);
String attachmentContent = Base64.getMimeEncoder().encodeToString(attachmentContentBytes);
String s = Base64.getEncoder().encodeToString(attachmentContentBytes);
attachments.setContent(s);
mail.addAttachments(attachments);
SendGrid sg = new SendGrid("sendgrid api key");
Request request = new Request();
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
if (response != null) {
return true;
} else {
return false;
}
}
Define above static method and call with relevant arguments as your program wants.
Here is the code of a servlet that sends a mail with a PDF as attachment, through Sendgrid:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
....
ByteArrayOutputStream os = null;
try {
PDFGenerator pdfGenerator = new PDFGenerator(invoiceOut);
os = pdfGenerator.getPDFOutputStream();
} catch (Exception e) {
....
}
SendGrid sendgrid = new SendGrid(Constants.SENDGRID_API_KEY);
SendGrid.Email email = new SendGrid.Email();
email.addTo(....);
email.setFrom(....);
email.setFromName(....);
email.setSubject(....);
email.setHtml("......");
ByteBuffer buf = null;
if (os == null) {
//error...
} else {
buf = ByteBuffer.wrap(os.toByteArray());
}
InputStream attachmentDataStream = new ByteArrayInputStream(buf.array());
try {
email.addAttachment("xxxxx.pdf", attachmentDataStream);
SendGrid.Response response = sendgrid.send(email);
} catch (IOException e) {
....
throw new RuntimeException(e);
} catch (SendGridException e) {
....
throw new RuntimeException(e);
}
}
PDFGenerator is one of my classes in which getPDFOutputStream method returns the PDF as ByteArrayOutputStream.
I personally find it easier to directly construct the JSON request body as described in the API docs than to use Sendgrid's libraries. I only use the Sendgrid library for sending the request after I construct the JSON data myself.
When constructing the JSON data you need to specify at least a filename and the content (i.e., the PDF file). Make sure to Base64 encode the PDF file before adding it to the JASON data.
I'd include some code, but I do Python and not Java so not sure that would help.

Can't get content-disposition from http.get header?

I am trying to download a file using web API + Angularjs and it's working fine, however I'm sending 'content-disposition' in the header from the web API but I'm unable to access it in the response-header.
WebAPI:
[HttpGet]
[AllowCrossSiteJson]
public HttpResponseMessage GetAcquisitionsTemplate()
{
var docContent = _d.FirstOrDefault();
Stream stream = new MemoryStream(docContent.Content);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
string contentDisposition = string.Concat("attachment; filename=", docContent.Name.Replace(" ", String.Empty), "." + docContent.Extension);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(contentDisposition);
return result;
}
Client Side (AngularJs):
$http.get(url)success(function (data, status, headers) {
var header= headers();
})
In the header I'm getting the following values but I'm unable to get content-disposition. Please correct me where I'm wrong?
I guess you are trying to hit it from localhost while the file is hosted on the server, in that case ask your server team to allow , Access-Control-Expose-Headers(‘Content-Disposition’) . With this Header, custom headers like COntent-Disposition will be accessible to you over cross domain

DART & GAE : Why a POST method send from dart can't be evaluate in GAE?

I have a Dart code used to send an HttpRequest with a POST method to my GAE WepApp2 application. The dart code is executed in chromium and serve by Chrome dev editor. I add in my GAE code some headers to avoid the XHR error in the client side.
The dart code send the datas to my GAE app but I can't read the data with self.request.POST.get("language")) and the app never enter in def post(self): section but with self.request.body I can read the data.
Could you explain that and provide some correction to have a full POST compliant code?
dart:
void _saveData() {
HttpRequest request = new HttpRequest(); // create a new XHR
// add an event handler that is called when the request finishes
request.onReadyStateChange.listen((_) {
if (request.readyState == HttpRequest.DONE &&
(request.status == 200 || request.status == 0)) {
// data saved OK.
print(request.responseText);
}
});
// POST the data to the server
var url = "http://127.0.0.1:8080/savedata";
request.open("POST", url, async: false);
String jsonData = JSON.encode({"language":"dart"});
request.send(jsonData);
}
GAE code in my handler:
def savedata(self):
logging.info("test")
logging.info(self.request.body)
logging.info(self.request.POST.get("language"))
def post(self):
logging.info("test 2")
logging.info(self.request.POST.get("language"))
self.response.headers["Access-Control-Allow-Origin"] = "http://127.0.0.1:49981"
self.response.headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
In Dart, if you don't specify request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") in your HttpRequest, the data is considered by GAE like a bite stream and you can only read them with self.request.body
If you add the Content-Type header in Dart you need also to change the data formating. In my case I mimic a form sending with POST method so I change String jsonData = JSON.encode({"language":"dart"}); by String jsonData = "language=dart2";
IN GAE python I can now read the data with self.request.POST.get("language")
If you need to send a JSON from DART to GAE, you can encode the string like this:
String jsonData = JSON.encode({"test":"valuetest1"});
String datas = "datas=$jsonData";
request.send(datas);
In GAE you can read the datas like this:
my_json = json.loads(self.request.POST.get("datas"))
logging.info(my_json["test"])
The complete code:
Dart
void _saveData2() {
String url = "http://127.0.0.1:8080/savedata";
HttpRequest request = new HttpRequest()
..open("POST", url, async: true)
..setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
..responseType = "arraybuffer";
String jsonData = JSON.encode({"test":"valuetest1"});
String datas = "datas=$jsonData";
request.send(datas);
}
GAE
class PageHandler(webapp2.RequestHandler):
def savedata(self):
self.response.headers.add_header('Access-Control-Allow-Origin', '*')
self.response.headers['Content-Type'] = 'application/json'
#logging.info(self.request)
my_json = json.loads(self.request.POST.get("datas"))
logging.info(my_json["test"])

Web api large file download with HttpClient

I have a problem with large file download from the web api to the win forms app. On the win form app I'm using HttpClient for grabbing data. I have following code on server side:
[HttpPost]
[Route]
public async Task<HttpResponseMessage> GetBackup(BackupRequestModel request)
{
HttpResponseMessage response;
try
{
response = await Task.Run<HttpResponseMessage>(() =>
{
var directory = new DirectoryInfo(request.Path);
var files = directory.GetFiles();
var lastCreatedFile = files.OrderByDescending(f => f.CreationTime).FirstOrDefault();
var filestream = lastCreatedFile.OpenRead();
var fileResponse = new HttpResponseMessage(HttpStatusCode.OK);
fileResponse.Content = new StreamContent(filestream);
fileResponse.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return fileResponse;
});
}
catch (Exception e)
{
logger.Error(e);
response = Request.CreateResponse(HttpStatusCode.InternalServerError);
}
return response;
}
on client side:
private async void btnStart_Click(object sender, EventArgs e)
{
var requestModel = new BackupRequestModel();
requestModel.Username = txtUsername.Text;
requestModel.Password = txtPassword.Text;
requestModel.Path = txtServerPath.Text;
var client = new HttpClient();
var result = await client.PostAsJsonAsync("http://localhost:50116/api/backup", requestModel);
var stream = await result.Content.ReadAsStreamAsync();
var localPath = #"d:\test\filenew.bak";
var fileStream = File.Create(localPath);
stream.CopyTo(fileStream);
fileStream.Close();
stream.Close();
fileStream.Dispose();
stream.Dispose();
client.Dispose();
}
}
This is actually working, but the purpose of this program is to grab large files over 3GB and save it to the client.
I have tried this on files sized 630MB what I notice is: When I call web api with http client, http client actually loads 630MB in the memory stream, and from the memory stream to the file stream, but when I try to load a different file I'm getting OutOfMemoryException. This is happening because the application doesn't release memory from the previous loaded file. I can see in task manager that it is holding 635MB of ram memory.
My question is how can I write data directly from HttpClient to file without using memory stream, or in other words how can I write data to file while HttpClient is downloading data?
To make the request, use a SendAsync overload that allows you to specify a HttpCompletionOption and use ResponseHeadersRead. You'll have to manually build the request though, without using the PostAsJsonAsync convenience method.

Resources