zowe / zowe-client-java-sdk

Zowe Client Java SDK
Eclipse Public License 2.0
23 stars 8 forks source link

Retrieve z/OSMF JSON error report document #268

Closed frankgiordano closed 1 year ago

frankgiordano commented 1 year ago

Currently any http request failure does not retrieve the IBM z/OSMF's JSON error report document which provides information on why the REST API request failed. This is an example of such a response:

The following http GET request will result in an HTTP 500 error: https://xxxxxxx.broadcom.net:xxxx/zosmf/restfiles/ds?

and the JSON error report document body response is: {"rc":4,"reason":13,"category":1,"message":"query parm dslevel= or volser= must be specified"}

The org.apache.http library used for this project does not support the retrieval of such reply body for an error condition.

I found a Java HTTP library that will retrieve the error body response, see: https://www.baeldung.com/unirest

frankgiordano commented 1 year ago

Here is a code snippet that reproduces the error condition noted above and retrieves the error JSON response using unirest:

package org.example;

import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] args) throws UnirestException, URISyntaxException {

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Basic xxxxxxxxxx");
        headers.put("Content-Type", "application/json");
        headers.put("X-CSRF-ZOSMF-HEADER", "true");
        headers.put("X-IBM-Max-Items", "22");
        headers.put("X-IBM-Attributes", "base");
        String url = "https://xxxxxxx.broadcom.net:xxxx/zosmf/restfiles/ds?";
        URI uri = new URI(url);

        HttpResponse<JsonNode> jsonResponse
                = Unirest.get(String.valueOf(uri))
                .headers(headers)
                .asJson();

        System.out.println(jsonResponse.getBody());
        System.out.println(jsonResponse.getStatus());
    }

}

Execution output:

{"rc":4,"reason":13,"category":1,"message":"query parm dslevel= or volser= must be specified"}
500

Process finished with exit code 0
frankgiordano commented 1 year ago

We can refactor the project to report on the error state with more details now if we decide to use UNIREST. We can update the Response class to contain a new member variable returnCode (rc). Then a Response object will be something like: returnCode (rc) = 4, responsePhrase (message) = "query parm dslevel= or volser= must be specified", statusCode = 500.

and as such we can report on the response body details and remove all the speculation descriptions for an error code that we currently supply the end user for an HTTP error condition.

frankgiordano commented 1 year ago

@corinned FYI see above!!

frankgiordano commented 1 year ago

Here is the top list of http java libraries https://mvnrepository.com/open-source/http-clients?p=1

Unirest is number 17 on the list. I wonder if others might have more pros than unirest. Something to investigate in the future.

For unirest I imported:

    <dependency>
        <groupId>com.mashape.unirest</groupId>
        <artifactId>unirest-java</artifactId>
        <version>1.4.9</version>
    </dependency>

for this project.

But this group and artifact was latest updated 2016.

The active unirest library seems to be from: https://github.com/Kong/unirest-java http://kong.github.io/unirest-java/

with:

com.konghq unirest-java-core 4.0.0-RC7

Might stay with the older one for now and see how it performs. The new one requires Java 11 which is fine, but there are thoughts to make this SDK Java 8+ compatible in the future. Would it be doable or needed, not sure something to keep in mind of.

frankgiordano commented 1 year ago

Keep in mind if need to deal with SSL certificate errors and ignore them as discussed here: https://stackoverflow.com/questions/2703161/how-to-ignore-ssl-certificate-errors-in-apache-httpclient-4-0 which we implement in the following method: /**

Not sure how to do this with unirest yet.

frankgiordano commented 1 year ago

Found the following for unirest that might deal with SSL errors: verifySsl(boolean) | toggle enforcing SSL | true or by default unirest will ignore them. Need to verify via a test first before looking into the verifySsl setting. See Configuration section in the following link that explain verifySsl implementation: http://kong.github.io/unirest-java/ might require the newer group/artifact

frankgiordano commented 1 year ago

I am almost finished implementing unirest for all rest api calls currently provided by the SDK. See the PR link to this issue. I am planning to keep the legacy rest processing in place and introduce the unirest layer via unirest packages that end users can easily switch for testing. All the class names and api methods are the same as legacy.

frankgiordano commented 1 year ago

Marking this as a PREVIEW FEATURE in the readme file. It will then eventually replace legacy http processing if all continues to go well.

frankgiordano commented 1 year ago

Changed unirest-java maven import to the following:

    <dependency>
        <groupId>com.konghq</groupId>
        <artifactId>unirest-java</artifactId>
        <version>3.14.2</version>
    </dependency>

Project moved to this groupId and is being maintained and does not contain any vulnerability which the older import did.

frankgiordano commented 1 year ago

Need to bypass certificate verification errors as done in legacy. See https://stackoverflow.com/questions/69375468/how-to-ignore-ssl-certificate-errors-in-apache-httpcomponents-httpclient-5-1 https://stackoverflow.com/questions/23242197/how-to-make-unirestjava-ignore-certificate-error