Ameritrade API POST Request JSON Response - java

I haven't coded in JAVA for years, and am trying to put an algorithm together to automatically make trades based on certain conditions.
I'm hoping to use the Ameritrade API
I've tried sending a cURL message in command prompt and I do indeed get a response back from the server 'Invalid Key'. I'd like to see the 'Invalid Key' response come back in Java as this will prove that I can send POST and receive JSON objects back into Java. From there I will work at authenticating but one step at a time!
Here's the curl message sent in command prompt that works, try it yourself by copying and pasting::
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=authorization_code&refresh_token=&access_type=offline&code=&client_id=&redirect_uri=" " https://api.tdameritrade.com/v1/oauth2/token
The first thing I'd like to do is be able to send this curl message in JAVA and receive the JSON response back in JAVA
This is what I have for code so far, but I get a 500 error, which makes me think its something with the way im sending the message to the server?
public void trytoAuthenticate() {
HttpURLConnection connection = null;
//
//this is the curl message in command prompt you can send to receive JSON response back
//curl -X POST --header "Content-Type: application/x-www-form-urlencoded" -d
//"grant_type=authorization_code&
//refresh_token=&
//access_type=offline&
//code=&
//client_id=&
//redirect_uri=" "https://api.tdameritrade.com/v1/oauth2/token"
try {
//Create connection
URL url = new URL("https://api.tdameritrade.com/v1/oauth2/token");
String urlParameters = "grant_type=" + URLEncoder.encode("authorization_code", "UTF-8") +
"&refresh_token=" + URLEncoder.encode("", "UTF-8") +
"&access_type=" + URLEncoder.encode("", "UTF-8") +
"&code=" + URLEncoder.encode("", "UTF-8") +
"&client_id=" + URLEncoder.encode("", "UTF-8") +
"&redirect_uri=" + URLEncoder.encode("", "UTF-8");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST"); //-X
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //-H
connection.setRequestProperty("Content-Length",
Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoOutput(true);//connection will be output
connection.setDoInput(true);//connection will be input
//Send request
DataOutputStream wr = new DataOutputStream (connection.getOutputStream());
wr.writeBytes(urlParameters);
System.out.println(urlParameters); //added for testing
wr.close();
//Get Response
DataInputStream is = new DataInputStream (connection.getInputStream());
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
rd.readLine();
//StringBuffer response = new StringBuffer(); // or StringBuffer/StringBuilder if Java version 5+
//String line;
//while ((line = rd.readLine()) != null) {
// response.append(line);
// response.append('\r');
//}
rd.close();
//System.out.println(response.toString());
//return response.toString();
} catch (Exception e) {
e.printStackTrace();
//return null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}

A few things:
You need four parameters: grant_type, access_type, redirect_url and code.
You should URLDecode the authorization code you got from the browser login you probably just performed (as per their instructions)
Remove empty parameters, leave only what I mentioned above.
The redirect URL must match EXACTLY the redirect URL you added when you created your APP in the console.
If this is an app (looks like it), you probably have to set the access_type to "offline". Again see their documentation. Depends on your application.
grant_type should be "authorization_code", as that's what you want.

Related

How do I use GET method with sending json data in android?

API route in Python (Flask)
#app.route('/secret')
def secret():
if request.get_json(force=True)['key'] == 'secret key':
return jsonify(msg='Hello!')
It is working linux terminal
curl -iX GET -d '{"key":"secret key"}' localhost
Linux terminal output this
{"msg":"Hello!"}
It doesn't need to work in browser.
try{
HttpURLConnection connection = (HttpURLConnection)
new URL("http://<my local ip>/secret").openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.connect();
JSONObject jsonInput = new JSONObject();
jsonInput.put("key", "secret key");
OutputStream os = connection.getOutputStream();
byte[] input = jsonInput.toString().getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
os.flush();
os.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
return response.toString();
} catch (IOException | JSONException e) {
Log.e("MainActivity", "Error: " + e.getMessage());
}
Although the GET method is set to the connection request in my codes, a POST request is being sent to the Python server.
Python Interpreter
Is it impossible to fix this?
Request Body is not recommended in HTTP GET requests. See HERE
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
When you try to write on a URL, you are implicitly POSTing on it despite you had set GET as the HTTP method. At below lines:
OutputStream os = connection.getOutputStream();
byte[] input = jsonInput.toString().getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
For confirmation of my words see Writing to a URLConnection
writing to a URL is often called posting to a URL. The server
recognizes the POST request and reads the data sent from the client.

curl and Java program are treated differently by CouchDB

This question might be a little bit naive...
I have written a small Java program that should query a CouchDB instance. However, CouchDB constantly returns that my user is not authorized. Using the same URL with curl works.
The Java Code:
HttpGet request = new HttpGet("http://admin:PASSWORD#localhost:5984/ecm_ng_nonpart/_security");
request.addHeader("accept", "application/xml");
try {
System.out.println("Executing request " + request.getMethod() + " " + request.getUri());
ClassicHttpResponse resp = httpClient.execute(request);
BufferedReader br = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
The response:
{"error":"unauthorized","reason":"You are not authorized to access this db."}
The curl output:
C:\Users\joche>curl -X GET http://admin:PASSWORD#localhost:5984/ecm_ng_nonpart/_security
{"members":{"roles":["_admin"],"names":["ecmnp","admin"]},"admins":{"roles":["_admin"],"names":["admin"]}}
Any idea what I am doing wrong?
Using the same URL with curl works.
Your posted information does not support this claim. Your URLs are different in the two cases.
Java: _sessions
HttpGet request = new HttpGet("http://admin:PASSWORD#localhost:5984/ecm_ng_nonpart/_sessions");
Curl: _security.
curl -X GET http://admin:PASSWORD#localhost:5984/ecm_ng_nonpart/_security

JSON POST Data via HttpURLConnection

I am trying to make a request to my RESTful API using Android and HttpURLConnection. The data must be sent in the JSON format via POST data.
Here is my code:
JSONObject check_request = new JSONObject();
check_request.put("username", username);
JSONObject request = BuildRequest(check_request, "username_check", false);
Log.i("DEBUG", request.toString());
// DEBUG OUTPUT: {"timestamp":1526900318,"request":{"username":"blubberfucken","type":"username_check"}}
URL request_url = new URL(apiURL);
HttpURLConnection connection = (HttpURLConnection)request_url.openConnection();
connection.setRequestProperty("User-Agent", "TheGameApp");
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "application/json; charset=UTF-8");
connection.setDoOutput(true);
connection.setDoInput(true);
OutputStream os = connection.getOutputStream();
os.write(request.toString().getBytes("UTF-8"));
os.flush();
InputStream in = new BufferedInputStream(connection.getInputStream());
String result = "";
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF8"));
String str;
while ((str = br.readLine()) != null)
{
result += str;
}
Log.i("DEBUG", result);
//JSONObject result_json = new JSONObject(result);
os.close();
in.close();
connection.disconnect();
You can see the Debug output as a Comment. The Problem is that the API does not receive any POST data. I have used PHPs var_dump to dump $_POST and $_REQUEST which both are empty arrays.
What am I missing here?
As the question popped up if the API work. This cURL command works fine with the correct result (it is the same JSON data as the debugger printed):
curl -d '{"timestamp":1526900318,"request":{"username":"blubberfucken","type":"username_check"}}' -H "Content-Type: application/json" -X POST http://localhost/v1/api.php
Just for the sake of completeness: The example above is working. The solution to the problem was pa part in PHP on the server side, where I checked the content type and used strpos to search for application/json in $_SERVER['CONTENT-TYPE'] and switched the needle and haystack (thus searching for application/json; charset=UTF8 in the string application/json instead of the other way around).

How to POST in Java

I have something that looks like this:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIs
How would I go about using this in Java? I have all the information already so I wouldn't need to parse it.
Basically I need to POST with 3 different data and using curl has been working for me but I need to do it in java:
curl -d 'grant_type=assertion&assertion_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fjwt%2F1.0%2Fbearer&assertion=eyJhbGciOiJSUzI1NiIsInR5i' https://accounts.google.com/o/oauth2/token
I cut off some data so its easier to read so it wont work.
So a big problem is that the curl would work while most tutorials I try for Java would give me HTTP response error 400.
Like should I be encoding the date like this:
String urlParameters = URLEncoder.encode("grant_type", "UTF-8") + "="+ URLEncoder.encode("assertion", "UTF-8") + "&" + URLEncoder.encode("assertion_type", "UTF-8") + "=" + URLEncoder.encode("http://oauth.net/grant_type/jwt/1.0/bearer", "UTF-8") + "&" + URLEncoder.encode("assertion", "UTF-8") + "=" + URLEncoder.encode(encodedMessage, "UTF-8");
or not:
String urlParameters ="grant_type=assertion&assertion_type=http://oauth.net/grant_type/jwt/1.0/bearer&assertion=" + encodedMessage;
Using this as the code:
URL url = new URL(targetURL);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(urlParameters);
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
writer.close();
reader.close();
Use something like HttpClient or similar.
It can post pre-URL-encoded data to a URI, although I don't know if you could just throw a complete request body at it--might need to parse it out, but there are likely libraries for that as well.
Here's a simple example of Apache HttpClient with request body from their docs (slightly modified to show how the execute works):
HttpClient client = new HttpClient();
PostMethod post = new PostMethod("http://jakarata.apache.org/");
NameValuePair[] data = {
new NameValuePair("user", "joe"),
new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
int returnCode = client.execute(post);
// check return code ...
InputStream in = post.getResponseBodyAsStream();
See the Apache HttpClient site for more info, examples and tutorials. This link might help you too.

Imgur API request using Java returns 400 status

I am trying to send a GET request to the Imgur API to upload an image.
When I use the following code I receive a 400 status response from the Imgur server - which, according to the Imgur error documentation, means I am missing or have incorrect parameters.
I know the parameters are correct as I have tested them directly in the browser URL (which successfully uploads an image) - so I must not be adding the parameters correctly within the code:
private void addImage(){
String data = URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode("http://www.lefthandedtoons.com/toons/justin_pooling.gif", "UTF-8");
data += "&" + URLEncoder.encode("key", "UTF-8") + "=" + URLEncoder.encode("myPublicConsumerKey", "UTF-8");
// Send data
java.net.URL url = new java.net.URL("http://api.imgur.com/2/upload.json");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
Logger.info( line );
}
wr.close();
rd.close();
}
This code is based on the API examples provided by Imgur.
Can anyone tell me what I am doing wrong and how I may resolve the problem?
Thanks.
In this sample, imgur service returns 400 Bad Request status response with a non-empty body because of incorrect API key. In case of non successful HTTP response you shold read the response body from an error input stream. For example:
// Get the response
InputStream is;
if (((HttpURLConnection) conn).getResponseCode() == 400)
is = ((HttpURLConnection) conn).getErrorStream();
else
is = conn.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
And, by the way your example is POST, not GET, because you are sending the parameters in the request body instead of the URL.

Categories