I am writing a Java class to access a third-party public REST API web service, that is secured using a specific APIKey parameter.
I can access the required Json array, using the JsonNode API when I save the json output locally to a file.
E.g.
JsonNode root = mapper.readTree(new File("/home/op/Test/jsondata/loans.json"));
But, if I try to use the live secured web URL with JsonNode
E.g.
JsonNode root = mapper.readTree(url);
I am getting a:
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60))
which suggests that I have a type mismatch. But I am assuming that it is more likely to be a connection issue.
I am handling the connection to the REST service:
private static String surl = "https://api.rest.service.com/xxxx/v1/users/xxxxx/loans?apikey=xxxx"
public static void main(String[] args) {
try {
URL url = new URL(surl);
JsonNode root = mapper.readTree(url);
....
}
I have also tried to use:
URL url = new URL(surl);
HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
InputStream isr = httpcon.getInputStream();
JsonNode root = mapper.readTree(isr);
with the same result.
When I remove the APIKey I receive a Status 400 Error. So I think I must not be handling the APIKey parameter.
Is there way to handle the call to the secured REST service URL using JsonNode? I would like to continue to use the JsonNode API, as I am extracting just two key:value pairs traversing multiple objects in a large array.
Just try to simply read response into string and log it to see what's actually going on and why you do not receive JSON from server.
URL url = new URL(surl);
HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
InputStream isr = httpcon.getInputStream();
try (BufferedReader bw = new BufferedReader(new InputStreamReader(isr, "utf-8"))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = bw.readLine()) != null) { // read whole response
sb.append(line);
}
System.out.println(sb); //Output whole response into console or use logger of your choice instead of System.out.println
}
Related
I am trying to build a Java code to create users in AAD using MSAL and MS Graph API. Below is the code that I am using to create the user. I am able to retrieve the token successfully, however getting exception while trying to POST the request. What am I doing wrong?
public static void main(String[] args) throws Exception {
Map<String,Object> params = new LinkedHashMap<>();
params.put("givenName", "Test");
params.put("displayName", "ABC");
params.put("accountEnabled", true);
params.put("mailNickname","abc");
params.put("userPrincipalName","jcooper#demo.onmicrosoft.com");
StringBuilder postData = new StringBuilder();
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
int length =postDataBytes.length;
URL url = new URL("https://graph.microsoft.com/v1.0/users");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/json");
conn.setRequestProperty("Authorization", "Bearer "+accessToken);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(false);
conn.setRequestProperty("Content-Length",Integer.toString(length));
conn.connect();
conn.getInputStream();
try (var wr = new DataOutputStream(conn.getOutputStream())) {
wr.write(postDataBytes);
}
StringBuilder content;
System.out.println(postDataBytes+" "+postData);
try (var br = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
String line;
content = new StringBuilder();
while ((line = br.readLine()) != null) {
content.append(line);
content.append(System.lineSeparator());
}
}
System.out.println(content.toString());
}
Exception : Exception in thread "main" java.io.IOException: Server returned HTTP response code: 411 for URL: https://graph.microsoft.com/v1.0/users
According to some test, I met the same issue with yours. It seems the code is correct but do not know why it still show 411 error. It may be caused by the graph api can just accept json request body but you convert the request body to application/x-www-form-urlencoded in your first part of code(I'm not sure because I test the code with json request body but still show 411).
Since you mentioned use MSAL to get access token, you can also continue to use MSAL to create the user. Please refer to this example:
GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient();
User user = new User();
user.accountEnabled = true;
user.displayName = "Adele Vance";
user.mailNickname = "AdeleV";
user.userPrincipalName = "AdeleV#contoso.onmicrosoft.com";
PasswordProfile passwordProfile = new PasswordProfile();
passwordProfile.forceChangePasswordNextSignIn = true;
passwordProfile.password = "xWwvJ]6NMw+bWH-d";
user.passwordProfile = passwordProfile;
graphClient.users()
.buildRequest()
.post(user);
For accessing Microsoft Graph from a desktop app, I'd use the InteractiveBrowserCredentialBuilder() with the TokenCredentialAuthProvider that comes with GraphSDK to get the Graph token. Check out the great sample code here. All you'd need to do to customize this is to change the last line and set the scopes differently based on what Graph API you need to call. There's a link on the bottom of that page that'll teach you to register your app properly.
The simplest way in a web app is to use Azure AD Spring Boot Starter to get an access token for a logged-in user, and use GraphSDK to call Graph in a Spring 5 web app. See this sample that demonstrates this along with full instructions (Relevant Graph code is is in SampleController.java and Utilities.java)
I followed this guide to create my own REST API. I am trying to consume my API that I built from the guide but I ran into some trouble when it came to using any request that wasn't a GET request. When I tried doing a delete request. (http://localhost:8080/api/v1/employees/3)
I would get a 405 error and I'm not sure why (I do not have any password protection in my local host). I want to understand how I can create requests other than GET. I tried using query parameters for my POST request, but it was unsuccessful.
I looked at all the other StackOverFlow Similar Questions and I couldn't find anything.
EDIT1: I am using a simple Java Application to do this.
This was the code I used in order to do my GET requests
String urlString = "http://localhost:8080/api/v1/employees";
try {
String result = "";
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
BufferedReader rd = new BufferedReader (new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
result += line;
}
rd.close();
System.out.println(result);
}
Try to replace this URLConnection conn = url.openConnection();
to this:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
you can use org.springframework.web.client.RestTemplate (rest-template) to consume rest api.
for delete, you can do something like
private void deleteEmployee() {
Map < String, String > params = new HashMap < String, String > ();
params.put("id", "1");
RestTemplate restTemplate = new RestTemplate();
restTemplate.delete(DELETE_EMPLOYEE_ENDPOINT_URL, params);
}
please check https://www.javaguides.net/2019/06/spring-resttemplate-get-post-put-and-delete-example.html and https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html and https://www.baeldung.com/rest-template
hope these provide enough info
I want to do an online xml request in java but the server responds with 401 error that means that there is an authentication that is need to access the server. I have the certfile.cer that i can use to do the authentication but i dont know how to load it in java.How can I achieve this in java? Here is part of my code.
StringBuilder answer = new StringBuilder();
URL url = new URL("www.myurl.com");
URLConnection conn = url.openConnection();
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(xml);
writer.flush();
String line;
while ((line = reader.readLine()) != null)
{
answer.append(line);
}
When using this code below to make a get request:
private String get(String inurl, Map headers, boolean followredirects) throws MalformedURLException, IOException {
URL url = new URL(inurl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(followredirects);
// Add headers to request.
Iterator entries = headers.entrySet().iterator();
while (entries.hasNext()) {
Entry thisEntry = (Entry) entries.next();
Object key = thisEntry.getKey();
Object value = thisEntry.getValue();
connection.addRequestProperty((String)key, (String)value);
}
// Attempt to parse
InputStream stream = connection.getInputStream();
InputStreamReader isReader = new InputStreamReader(stream );
BufferedReader br = new BufferedReader(isReader );
System.out.println(br.readLine());
// Disconnect
connection.disconnect();
return connection.getHeaderField("Location");
}
The resulting response is completely nonsensical (e.g ���:ks�6��9�rђ� e��u�n�qש�v���"uI*�W��s)
However I can see in Wireshark that the response is HTML/XML and nothing like the string above. I've tried a myriad of different methods for parsing the InputStream but I get the same result each time.
Please note: this only happens when it's HTML/XML, plain HTML works.
Why is the response coming back in this format?
Thanks in advance!
=== SOLVED ===
Gah, got it!
The server is compressing the response when it contains XML, so I needed to use GZIPInputStream instead of InputSream.
GZIPInputStream stream = new GZIPInputStream(connection.getInputStream());
Thanks anyway!
use an UTF-8 encoding in input stream like below
InputStreamReader isReader = new InputStreamReader(stream, "UTF-8");
I am trying to make Rest service call in Java. I am new to web and Rest service. I have Rest service which returns JSON as response. I have the following code but I think it's incomplete because I don't know how to process output using JSON.
public static void main(String[] args) {
try {
URL url = new URL("http://example.com:7000/test/db-api/processor");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("PUT");
connection.setRequestProperty("Content-Type", "application/json");
OutputStream os = connection.getOutputStream();
//how do I get json object and print it as string
os.flush();
connection.getResponseCode();
connection.disconnect();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
I am new to Rest services and JSON.
Since this is a PUT request you're missing a few things here:
OutputStream os = conn.getOutputStream();
os.write(input.getBytes()); // The input you need to pass to the webservice
os.flush();
...
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream()))); // Getting the response from the webservice
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output); // Instead of this, you could append all your response to a StringBuffer and use `toString()` to get the entire JSON response as a String.
// This string json response can be parsed using any json library. Eg. GSON from Google.
}
Have a look at this to have a more clear idea on hitting webservices.
Your code is mostly correct, but there is mistake about OutputStream.
As R.J said OutputStream is needed to pass request body to the server.
If your rest service doesn't required any body you don't need to use this one.
For reading the server response you need use InputStream(R.J also show you example) like that:
try (InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();) {
byte[] buf = new byte[512];
int read = -1;
while ((read = inputStream.read(buf)) > 0) {
byteArrayOutputStream.write(buf, 0, read);
}
System.out.println(new String(byteArrayOutputStream.toByteArray()));
}
This way is good if you don't want to depends on third-part libraries. So I recommend you to take a look on Jersey - very nice library with huge amount of very useful feature.
Client client = JerseyClientBuilder.newBuilder().build();
Response response = client.target("http://host:port").
path("test").path("db-api").path("processor").path("packages").
request().accept(MediaType.APPLICATION_JSON_TYPE).buildGet().invoke();
System.out.println(response.readEntity(String.class));
Since your Content-Type is application/json, you could directly cast the response to a JSON object for example
JSONObject recvObj = new JSONObject(response);
JsonKey jsonkey = objectMapper.readValue(new URL("http://echo.jsontest.com/key/value/one/two"), JsonKey.class);
System.out.println("jsonkey.getOne() : "+jsonkey.getOne())