Adding value to path parameter in Java REST? - java

NOTICE UPDATE!!
The problem got solved and i added my own answer in the thread
In short, I have attempted to add the parameter "scan_id" value but since it is a POST i can't add the value directly in the url path.
using the code i already have, how would i go about modifying or adding so that the url is correct, that is, so that it accepts my POST?.
somehow i have been unable to find any examples that have helped me in figuring out how i would go about doing this..
I know how to do a POST with a payload, a GET with params. but a post with Params is very confusing to me.
Appreciate any help. (i'd like to continue using HttpUrlConnection unless an other example is provided that also tells me how to send the request and not only configuring the path.
I've tried adding it to the payload.
I've tried UriBuilder but found it confusing and in contrast with the rest of my code, so wanted to ask for help with HttpUrlConnection.
URL url = new URL("http://localhost/scans/{scan_id}/launch");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("tmp_value_dont_mind_this", "432432");
con.setRequestProperty("X-Cookie", "token=" + "43432");
con.setRequestProperty("X-ApiKeys", "accessKey="+"43234;" + " secretKey="+"43234;");
con.setDoInput(true);
con.setDoOutput(true); //NOT NEEDED FOR GETS
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
//First example of writing (works when writing a payload)
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
//second attemp at writing, doens't work (wanted to replace {scan_id} in the url)
DataOutputStream writer = new DataOutputStream(con.getOutputStream());
writer.writeChars("scan_id=42324"); //tried writing directly
//writer.write(payload);
writer.close();
Exception:
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 400 for URL: http://localhost/scans/launch
I'd like one of the three response codes because then i know the Url is correct:
200 Returned if the scan was successfully launched.
403 Returned if the scan is disabled.
404 Returned if the scan does not exist.
I've tried several urls
localhost/scans/launch,
localhost/scans//launch,
localhost/scans/?/launch,
localhost/scans/{scan_id}/launch,

So with the help of a friend and everyone here i solved my problem.
The below code is all the code in an entire class explained bit by bit. at the bottom you have the full class with all its syntax etc, that takes parameters and returns a string.
in a HTTP request there are certain sections.
Such sections include in my case, Request headers, parameters in the Url and a Payload.
depending on the API certain variables required by the API need to go into their respective category.
My ORIGINAL URL looked like this: "http://host:port/scans/{scan_id}/export?{history_id}"
I CHANGED to: "https://host:port/scans/" + scan_Id + "/export?history_id=" + ID;
and the API i am calling required an argument in the payload called "format" with a value.
String payload = "{\"format\" : \"csv\"}";
So with my new URL i opened a connection and set the request headers i needed to set.
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
The setDoOutput should be commented out when making a GET request.
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("X-Cookie", "token=" + token);
con.setRequestProperty("X-ApiKeys", "accessKey="+"23243;" +"secretKey="+"45543;");
Here i write to the payload.
//WRITING THE PAYLOAD to the http call
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
After i've written the payload i read whatever response i get back (this depends on the call, when i do a file download (GET Request) i don't have a response to read as i've already read the response through another piece of code).
I hope this helps anyone who might encounter this thread.
public String requestScan(int scan_Id, String token, String ID) throws MalformedInputException, ProtocolException, IOException {
try {
String endpoint = "https://host:port/scans/" + scan_Id + "/export?history_id=" ID;
URL url = new URL(endpoint);
String payload= "{\"format\" : \"csv\"}";
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("X-Cookie", "token=" + token);
con.setRequestProperty("X-ApiKeys", "accessKey="+"324324;" +
"secretKey="+"43242;");
//WRITING THE PAYLOAD to the http call
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
//READING RESPONSE
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuffer jsonString = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
jsonString.append(line);
}
br.close();
con.disconnect();
return jsonString.toString();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}

As discussed here the solution would be to change the content type to application/x-www-form-urlencoded, but since you are already using application/json; charset=UTF-8 (which I am assuming is a requirement of your project) you have no choise to redesign the whole thing. I suggest you one of the following:
Add another GET service;
Add another POST service with content type application/x-www-form-urlencoded;
Replace this service with one of the above.
Do not specify the content type at all so the client will accept anything. (Don't know if possible in java)
If there are another solutions I'm not aware of, I don't know how much they would be compliant to HTTP protocol.
(More info)
Hope I helped!

Why you are not using like this. Since you need to do a POST with HttpURLConnection, you need to write the parameters to the connection after you have opened the connection.
String urlParameters = "scan_id=42324";
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
dataOutputStream.write(postData);
Or if you have launch in the end, just change the above code to the following,
String urlParameters = "42324/launch";
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
dataOutputStream.write(postData);

URL url = new URL("http://localhost/scans/{scan_id}/launch");
That line looks odd to me; it seems you are trying to use a URL where you are intending the behavior of a URI Template.
The exact syntax will depend on which template implementation you choose; an implementation using the Spring libraries might look like:
import org.springframework.web.util.UriTemplate;
import java.net.url;
// Warning - UNTESTED code ahead
UriTemplate template = new UriTemplate("http://localhost/scans/{scan_id}/launch");
Map<String,String> uriVariables = Collections.singletonMap("scan_id", "42324");
URI uri = template.expand(uriVariables);
URL url = uri.toURL();

Related

JSON in java by POST getting None return

I request POST by this code
URL url = new URL("adress/discordnotifi");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setReadTimeout(5000);
httpURLConnection.setConnectTimeout(5000);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.connect();
JSONObject object = new JSONObject();
myPWord = ((EditText) (findViewById(R.id.edit_Id))).getText().toString();
object.put("token", tokens);
object.put("discordid", mydiscord);
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(object.toString().getBytes("UTF-8"));
Log.d("debug",object.toString());
outputStream.flush();
outputStream.close();
and my tokens and mydiscord is the information that I want to send as JSON format like
{"token":"tokens","discordid":"mydiscord"}
and from python flask
#app.route('/discordnotifi', methods=['POST'])
def post():
content = request.json
print(content)
Discordid = int(content["discordid"])
token = content['token']
"""Discordid = request.form.get("discordid")
token = request.form.get("token")"""
print(Discordid, token)
return ("Thx")
at print(content) I get None I really don't know whts wrong here. I was planning to send Json with information but I getting None from Json.
The very least you're missing is enabling output on the connection. Add:
httpURLConnection.setDoOutput(true);
The server may also require that you set some headers, for example content-type to tell it that you are sending JSON.
httpURLConnection.setRequestProperty("Content-Type", "application/json; utf-8");
If you can use Java 11, consider using the new HttpClient class instead of HttpUrlConnection. It simplifies creating correct requests.

HttpURLConnection post method issue

I have a problem on HttpURLConnection in post method. Everything is working fine on get method however, when I try to use Post method. I'm getting this error message.
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL
Here's my code snippet. I hope you could help me about this.
URL url = new URL(my url/userInfo);
String encoding = Base64.getEncoder().encodeToString(("username:password").getBytes("UTF-8"));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "text/plain");
connection.setRequestProperty("Authorization", "Basic " + encoding);
connection.setRequestProperty("x-csrf-token", "fetch");
String csrfToken = connection.getHeaderField("x-csrf-token");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
String output = in.readLine();
in.close();
String content = data // expected data to retrieve
URL url2 = new URL(my URL);//another url to push the data retrieve
HttpURLConnection connection2 = (HttpsURLConnection) url2.openConnection();
connection2.setDoInput(true);
connection2.setDoOutput(true);
connection2.setRequestMethod("POST");
connection2.setRequestProperty("Authorization", "Basic " + encoding);
connection2.setRequestProperty("Accept", "application/json");
connection2.setRequestProperty("x-CSRFToken", csrfToken);
connection2.setRequestProperty("cache-control", "no-cache");
OutputStream os = connection2.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
osw.write(data);//this is where the data will be pushed
osw.flush();
osw.close();
os.close();
the idea is, we need first to get the x-csrf-token and data from the first link, which is okay. After GET Method execution, the POST method will occur. unfortunately, the post method is not working. I'm getting the error message shown above. By the way, we tried to do a post method in POSTMAN and it' working fine.
Hoping you could help me about this.

Why HttpURLConnection does not send data unless I try to receive something

I cannot comprehend why doesn't the following code does not put a packet onto wire (confirmed via wireshark). It is a fairly standard method of sending an HTTP POST request, as I believe. I don't intend to read anything just POST.
private void sendRequest() throws IOException {
String params = "param=value";
URL url = new URL(otherUrl.toString());
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setDoOutput(true);
con.setDoInput(true); //setting this to `false` does not help
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "text/plain");
con.setRequestProperty("Content-Length", "" + Integer.toString(params.getBytes().length));
con.setRequestProperty("Accept", "text/plain");
con.setUseCaches(false);
con.connect();
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(params);
wr.flush();
wr.close();
//Logger.getLogger("log").info("URL: "+url+", response: "+con.getResponseCode());
con.disconnect();
}
What happens is... actually nothing, unless I try to read anything. For example by uncommenting the above log line which reads the response code. Trying to read a response via con.getInputStream(); also works. There is no movement of packets. When I uncomment the getResponseCode, I can see that http POST is sent, and then 200 OK is sent back. The order is proper. I.e. I don't get some wild response before sending POST. Everything else looks exactly the same (I can attach wireshark screenshots if needed.). In the debugger the code executes (i.e. does not block anywhere).
I don't understand under what circumstances this can be happening. I belive it should be possible, to send a POST request with con.setDoInput(false);. Currently it doesn't send anything or fails (when trying to execute con.getResponseCode()) with an exception because I obviously promised I won't read anything.
It might be relevant, that before sendRequest I do request some data from the same site, but I trust I close everything properly. I.e:
public static String getData(String urlAddress) throws MalformedURLException, IOException {
URL url = new URL(urlAddress);
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setDoOutput(false);
InputStream in = con.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder data = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
data.append(line);
}
reader.close();
in.close();
con.getResponseCode();
con.disconnect();
return data.toString();
}
The server for url in both cases is the same, port also, so I believe it is possible to use the same socket for communication. The above code works and retrieves the data properly.
I am not sure, maybe I don't clean something, and it gets cached, so with out an explicit read the POST gets delayed. There is no other traffic on the socket.
Unless you're using fixed-length or chunked transfer mode, HttpURLConnection will buffer all your output until you call getInputStream() or getResponseCode(), so that it can send a correct Content-length header.
If you call getResponseCode() you should have a look at its value.

post data to server using Java, like jQuery's $.post()

I have a web backend, which works with the following jQuery post:
$.post(path + "login",
{"params": {"mode":"self", "username": "aaa", "password": "bbb"}},
function(data){
console.log(data);
}, "json");
How can I implement the same POST from Java, with HttpURLConnection? I'm trying with
URL url = new URL(serverUrl + loginUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length",
Integer.toString(postData.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream wr =
new DataOutputStream(connection.getOutputStream ());
wr.writeBytes(postData);
wr.flush ();
wr.close ();
BufferedReader br =
new BufferedReader(
new InputStreamReader(connection.getInputStream()));
, where postData = "{\"mode\": \"...\", ..... }"
but it doesn't work the same way.
The code on the server is written id Django, and tries to get the data in this way:
mode=request.POST.get("params[mode]")
You seem to be thinking all the time that jQuery sends JSON in its raw form to the server and that the HTTP server flawlessly understands it. This is not true. The default format for HTTP request parameters is application/x-www-form-urlencoded, exactly like as HTML forms in HTTP websites are using and exactly like as how GET query strings in URLs look like: name1=value1&name2=value2.
In other words, jQuery doesn't send JSON unmodified to the server. jQuery just transparently converts them to true request parameters. Pressing F12 in a sane browser and inspecting the HTTP traffic monitor should also have shown you that. The "json" argument which you specified there in end of $.post just tells jQuery which data format the server returns (and thus not which data format it consumes).
So, just do exactly the same as jQuery is doing under the covers:
String charset = "UTF-8";
String mode = "self";
String username = "username";
String password = "bbb";
String query = String.format("%s=%s&%s=%s&%s=%s",
URLEncoder.encode("param[mode]", charset), URLEncoder.encode(mode, charset),
URLEncoder.encode("param[username]", charset), URLEncoder.encode(username, charset),
URLEncoder.encode("param[password]", charset), URLEncoder.encode(password, charset));
// ... Now create URLConnection.
connection.setDoOutput(true); // Already implicitly sets method to POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
try (OutputStream output = connection.getOutputStream()) {
output.write(query.getBytes(charset));
}
// ... Now read InputStream.
Note: do NOT use Data(Input|Output)Stream! Those are for creating/reading .dat files.
See also:
Using java.net.URLConnection to fire and handle HTTP requests
You should use efficient libraries to build (valid) json objects. Here is an example from the PrimeFaces library:
private JSONObject createObject() throws JSONException {
JSONObject object = new JSONObject();
object.append("mode", "...");
return object;
}
If you wish to have a nice and clean code to send and retrieve objects, take a look at the answer from Emil Adz ( Sending Complex JSON Object ).

Picasa getAlbum request not working Android

String album = "http://picasaweb.google.com/data/feed/api/user/"+email;
HttpURLConnection con = (HttpURLConnection) new URL(albumUrl).openConnection();
// request method, timeout and headers
con.setRequestMethod("GET") ;
con.setReadTimeout(15000);
con.setRequestProperty("Authorization", "GoogleLogin auth="+auth);
con.setRequestProperty("GData-Version", "2");
// set timeout and that we will process output
con.setReadTimeout(15000);
con.setDoOutput(true);
// connnect to url
con.connect();
// read output returned for url
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
Problem : Everytime i call con.getInputStream() it gives me file not found exception.
But when i load the same url in the desktop browser then it is displaying correct data.
I am confused why on android it is throwing exception.
Thanks in advance.
Did you get this? Maybe you just missed the https
below example uses default for authenticated user and the experimental fields list.
url = "https://picasaweb.google.com/data/feed/api/user/default?kind=album&access=public&fields="
+ URLEncoder
.encode("entry(title,id,gphoto:numphotosremaining,gphoto:numphotos,media:group/media:thumbnail)",
"UTF-8");
https://developers.google.com/picasa-web/docs/2.0/developers_guide_protocol#ListAlbums

Categories

Resources