graphQL api requests stopped working suddenly - java

so I had some code that's been working for months but recently it's suddenly stopped. It makes a request to the Anilist api to get information about some anime.
try {
String query = getQuery();
query = query.replace("\n", " ").replace(" ", " ");
URL url = new URL("https://graphql.anilist.co");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.addRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
OutputStream os = conn.getOutputStream();
os.write(query.getBytes("UTF-8"));
os.close();
// read the response
InputStream in = new BufferedInputStream(conn.getInputStream());
String result = org.apache.commons.io.IOUtils.toString(in, "UTF-8");
in.close();
conn.disconnect();
//return result
} catch (Exception exp) {
System.out.println("exception TRIGGERED");
System.out.println(exp.getLocalizedMessage());
}
So I put in breakpoints and it seems to break at line after the comment "// read the response". I've tried the same request using the Altair GraphQL Client extension for google chrome and the suggested tool at https://anilist.co/graphiql and they both work, so the problem seems like it's with my code somehow, but I haven't updated my environment. I also have an instance of the code running on aws (it's part of a discord bot), and I know I haven't touched that since I put the bot up there.
If you're interested, one of the queries I know used to work is
{"query":"query {
Media (type: ANIME, search: "naruto") {
id
idMal
type
description(asHtml:false)
chapters
format
episodes
source
genres
averageScore
popularity
isAdult
status
nextAiringEpisode {
episode
airingAt
timeUntilAiring
}
startDate {
year
month
day
}
season
title {
english
native
romaji
}
coverImage{
large
medium
}
studios (isMain: true) {
nodes {
id
name
}
}
}
}"}
Any help is appreciated, Thank you very much.

Related

Microsoft Graph: Requesting an Extension returns http 400 bad request

I added an open extension to an event in a calendar and am trying to read it back.
Here is the url:
https://graph.microsoft.com/v1.0/users/{userid}/calendars/{calendarId}=/events?$expand=Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event')
I cannot get this to work in a Java program. The following combinations do work:
It works my Java program if I remove the $expand... parameter. I can also ask for certain fields, that works too.
The request works in Postman (I just have to set the token)
The request works in Graph Explorer when I log in as the owner of the calendar
Here is the extension (inside one of the events) when I use Postman to read the event. It is the last item in the event:
"extensions#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('{userid}')/calendars('{calendarId}')/events('{eventId})/extensions",
"extensions": [
{
"#odata.type": "#microsoft.graph.openTypeExtension",
"id": "Microsoft.OutlookServices.OpenTypeExtension.c.i.m.p.server.entities.outlook.Event",
"extensionName": "c.i.m.p.server.entities.outlook.Event",
"adherentId": "12346",
"timeSlotID": "346463"
}
]
Here is the Java code (Java 8, using java.io and java.net libraries):
private static void doSomething(String _accessToken) throws IOException {
String urlString = "https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events?$expand=Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event')";
URL url = new URL(urlString);
Proxy webProxy
= new Proxy(Proxy.Type.HTTP, new InetSocketAddress({proxy-address}, {port}));
HttpURLConnection connection = (HttpURLConnection) url.openConnection(webProxy);
// Set the appropriate header fields in the request header.
connection.setRequestProperty("Authorization", "Bearer " + _accessToken);
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setReadTimeout(5000);
connection.setRequestMethod(HttpMethod.GET);
try {
connection.connect();
int responseCode = connection.getResponseCode();
System.out.println("execute(), response code = " + responseCode);
String responseMessage = connection.getResponseMessage();
System.out.println("execute(), response Message = " + responseMessage);
String responseString = null;
try {
InputStream ins = connection.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(ins));
StringBuffer sb=new StringBuffer();
String line;
while ((line=br.readLine()) != null) {
sb.append(line);
}
responseString = sb.toString();
} catch (Exception e) {
System.out.println("Could not get input stream from response, error is " + e.toString());
}
System.out.println("execute(), httpResult = " + responseString);
} catch (IOException e) {
System.out.println(".execute(), IOException : " + e.toString());
} finally {
connection.disconnect();
}
}
How do I fix this? Thanks!
400 means bad request. It could be because of url encoding. Url encode the query string.
Something like
String query = "Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event'";
String url = "https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events?
$expand=" + URLEncoder.encode(query, StandardCharsets.UTF_8.name());
Alternatively you could use graph service java api based on your need which will help abstract all the interactions for you or you could use any of the rest clients available.
First of all, you should provide more info on the error - Stacktrace and error message. But 400 code indicates that was a user mistake, meaning that you are sending an invalid request. Since you say that postman request works then compare all the headers that are sent by postman and see if your code misses some hearer. As for the code, instead of coding your own Http client functionality I would suggest using 3d party Http client. Here are a few suggestions:
Apache Http client - very popular and well known 3d party Http Client
OK Http client - Open-source Http client. Here is tutorial
MgntUtils Http client - very simple 3d party HttpClient: Provided in MgntUtils Open source library (written by me). Very simple in use. Take a look at Javadoc. Library itself provided as Maven artifacts and on Git (including source code and Javadoc).

I have given correct parameters and headers for POST method, but response code is 400

I was trying to integrate SnapChat login kit to my web application. I was able to get the authorization code from the SnapChat, but I am having trouble getting the access token.
I have done FB, Google, Instagram login integration perfectly fine, but this one I am totally lost.
I have tried to encode the parameters, change the order of headers, but all the time it gives me 400 bad request.
try {
URL url = null;
if(service.equals(APIConstants.GOOGLE))
url = new URL(SNSIdentifications.GOOGLE_TOKEN_REQUEST_URL);
else if (service.equals(APIConstants.FACEBOOK))
url = new URL(SNSIdentifications.FACEBOOK_TOKEN_REQUEST_URL);
else if (service.equals(APIConstants.INSTAGRAM))
url = new URL(SNSIdentifications.INSTAGRAM_TOKEN_REQUEST_URL);
else
url = new URL(SNSIdentifications.SNAPCHAT_TOKEN_REQUEST_URL);
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
if(service.equals(APIConstants.SNAPCHAT)) {
// String userCredentials = URLEncoder.encode(client_id + ":" + secret, "UTF-8");
String userCredentials = client_id + ":" + secret;
byte[] data = Base64.getEncoder().encode(userCredentials.getBytes());
String authorizationHeaderBase64 = new String(data);
conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded" );
conn.setRequestProperty( "Authorization", "Basic " + authorizationHeaderBase64);
// conn.setRequestProperty("charset", "utf-8");
//Integer.toString(payload.getBytes(StandardCharsets.UTF_8).length)
// conn.setRequestProperty( "Content-Length", Integer.toString(payload.getBytes(StandardCharsets.UTF_8).length) );
writer = new OutputStreamWriter(conn.getOutputStream());
// writer.write(URLEncoder.encode(payload, "UTF-8"));
writer.write(params);
writer.flush();
System.out.println(conn.getResponseCode() + " " + conn.getResponseMessage() + " ");
} else {
writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(params);
writer.flush();
}
int responseCode = conn.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK) {
return new JSONObject(fetchResponse(conn));
}
} catch (IOException e) {
e.printStackTrace();
}
I should expect access token, refresh token, and expires_in values from the code above, but unfortunately it cannot, because of 400 bad request error.
I solved the problem. It turned out it was several combinations of problems.
When you are having an issue as I posted, please do check the followings:
Make sure you are using correct Client Id and Secret.
If you are adding Code Challenge and code challenge method parameters, you need to have code verifier to get access token. If you don't have these parameters, you don't need to worry about getting an access token.
When setting a header "Authorization" use base64 encode, not base16. (Snapchat page says base16, but in an example, it's in 64).
Check your urls, id, secret once again with those to get the authorization code.
:)

Java HTTP post assistance

I've been working with the Slack API in java and have been trying to get an HTTP method that can be used like my below example block of code. That code block works, but the issue is I need to also include a 200 response code, and can't figure out how to get it to work.
Basically, how can I, In Java, send an HTTP post and also tag on the 200 status code using the URL and the content?
Current code:
public void httpRequest(URL url, String content) {
try {
byte[] contentBytes = content.getBytes("UTF-8");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", Integer.toString(contentBytes.length));
connection.setRequestProperty("Status", Integer.toString(200));
OutputStream requestStream = connection.getOutputStream();
requestStream.write(contentBytes, 0, contentBytes.length);
requestStream.close();
String response = "";
BufferedReader responseStream;
response = "" + ((HttpURLConnection) connection).getResponseCode();
try {
if (((HttpURLConnection) connection).getResponseCode() == 200) {
responseStream = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
} else {
responseStream = new BufferedReader(new InputStreamReader(((HttpURLConnection) connection).getErrorStream(), "UTF-8"));
}
response = responseStream.readLine();
responseStream.close();
} catch (NullPointerException ignored) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
The call to setDoOutput(true) triggers a post, i.e. you do not need to add
connection.setRequestMethod("POST");
Adding a status header to the request is possible, as you have done, but typically one associates status codes with http responses, not requests. - And off course, adding such custom header would only make sense if the server was designed to use this information to anything.
See this big, and highly up-voted answer on java.net.HttpURLConnection.
Also, you have some problems relating to your response variable as well as the BufferedReader. You accidentally override the value you initially assigned to the response field, instead of concatening. Also, your readLine() should probably be in a loop:
String tmp;
while ((tmp = responseStream.readLine()) !=null){
response += tmp;
}

Download web page only if it has been modified

I'm building and app for an assessment and I need to download a web page only if it has been modified since the last time I downloaded it. I need to store the date of last change as an Long, so the method getDate() returns a long.
I tried to use HttpURLConnection and URLConnection, but I couldn't manage to achieve a solution.
Within my attempts I tried to use:
If-Modified-Since, but, somehow, I didn't receive the 304 response code, only the 200. The code:
HttpURLConnection huc = null;
try {
URL url = new URL(pages.get(0).getUrl());
huc = (HttpURLConnection) url.openConnection();
huc.setIfModifiedSince(pages.get(0).getDate());
huc.connect();
Log.d("App", "Since: " + huc.getIfModifiedSince());
Log.d("App", "Response: " + huc.getResponseCode());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//output
since: 1354320000000 - which is the return of the getDate method.
Response: 200
html etags, but I couldn't retrieve the information from the response, because the server doesn't answer the Last-Modified tag.
Thanks in advance

Problem with POSTing XML data to an API using Java

I'm having problem with sending XML-data using HTTP POST to an API.
If I send well formatted XML, I get an error message:
Server Exception: Cannot access a closed Stream
If the XML isn't well formatted, I get HTTP 500. And if I just send an empty string instead of a string with XML, I get back an error message: EMPTY REQUEST.
I don't have many ideas about what the error could be, but the connection works because the error message is returned in XML format. I'm just sending the XML data as a string. Is it possible that I am required to send an EOF or something in the end? And how do I do that in my Java code? Any other ideas about what the problem can be?
The API is made in .NET
Here is the Java code I'm using to POST the XML data:
Authenticator.setDefault(new MyAuthenticator());
String xmlRequestStatus =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><test><data>32</data></test>";
System.out.println(xmlRequestStatus);
String contentType = "text/xml";
String charset = "ISO-8859-1";
String request = null;
URL url = null;
HttpURLConnection connection = null;
OutputStream output = null;
InputStream response = null;
try {
url = new URL("http://127.0.0.1/test");
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", contentType);
output = connection.getOutputStream();
output.write(request.getBytes("ISO-8859-1"));
if(output != null) try { output.close(); } catch (IOException e) {}
response = connection.getInputStream();
....
It looks fine and should work fine. The connection.setRequestMethod("POST"); is however entirely superfluous when you already did connection.setDoOutput(true);.
Since this error is coming straight from the .NET webservice hosted at localhost, are you sure that it is written without bugs? I don't do .NET, but Google learns me that it's related to MemoryStream. I'd concentrate on the .NET code and retest/debug it. Maybe those related SO questions may help.
You need to specify method POST by doing something like this,
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Length", "" + length);
Otherwise, it's treated as a GET and some server doesn't expect body with GET so the stream is closed.
Maybe close the OutputStream later in the control flow. So instead of this:
output.write(request.getBytes("ISO-8859-1"));
if(output != null) try { output.close(); } catch (IOException e) {}
response = connection.getInputStream();
Try this (and maybe add the flush)?
output.write(request.getBytes("ISO-8859-1"));
output.flush();
response = connection.getInputStream();
if(output != null) try { output.close(); } catch (IOException e) {}
Shouldn't it be <32 instead of <32?
It looks like request is initialized to null, but afterwards not set. Should it not be
output.write(xmlRequestStatus.getBytes("ISO-8859-1"));

Categories