I have a cloud endpoint function that returns a json string as response. An api endpoint makes an http request to the cloud function. How can I return the json string response as it is. I tried the following(just as an example)
#ApiMethod(
name = "json",
httpMethod = ApiMethod.HttpMethod.GET
)
public JsonObject json()
{
String item = "{\"name\":\"Josh\",\"sex\":\"male\"}";
JsonParser jsonParser = new JsonParser();
return jsonParser.parse(item).getAsJsonObject();
}
and I get the following message
WARNING: exception occurred while invoking backend method
[INFO] GCLOUD: java.io.IOException: com.fasterxml.jackson.databind.JsonMappingException: JsonObject (through reference chain: endpoints.repackaged.com.google.gson.JsonObject["asInt"]
Caused by: java.lang.UnsupportedOperationException: JsonObject
I understand JSONObject is not part of the supported returned type, I just want to know how I can just output the json string response from the endpoint just as it is
What you can do is to wrap your JSON into a String (in your endpoint) and return the wrapper object. You wrapper object could be a simple POJO with only one String attribute. Then on your API consumer side, you just read the string (representing your JSON) and use it as you wish.
Related
I'm trying to consume API in React app but I'm getting this error in response.
{errorMessage: "An error occurred during JSON parsing", errorType: "java.lang.RuntimeException", stackTrace: Array(0), cause: {…}}
cause:
cause: {errorMessage: "Can not deserialize instance of java.lang.String o…MemoryAsInputStream#727803de; line: 1, column: 1]", errorType: "com.fasterxml.jackson.databind.JsonMappingException", stackTrace: Array(6)}
errorMessage: "com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token↵ at [Source: lambdainternal.util.NativeMemoryAsInputStream#727803de; line: 1, column: 1]"
errorType: "java.io.UncheckedIOException"
Here's the POST request made from React.
async handleSubmit(event) {
event.preventDefault();
const data = "{\"type\":\"select\",\"startdate\":\""+this.state.startdate+"\",\"enddate\":\""+this.state.enddate+"\"}";
const url = "<API Gateway endpoint>";
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: "{\"type\":\"select\",\"startdate\":\"2020-12-15 09:59:59\",\"enddate\":\"2021-01-13 21:37:43\"}"
});
const body = await response.json();
this.setState({invoices : body, isLoading:false})
console.log(this.state.invoices);
}
Most probably the issue is with the Java handler method not able to parse request data. I'm not sure how to structure the request body such that Lambda handler accepts the request body as input parameter.
public static String handleRequest(String input, Context context) {
Connection conn = createConnection();
Statement stmt = null;
JSONObject jsonObject = null;
<JDBC stuff>
return jsonObject.toString();
}
For API Gateway I think the Java handler class need to implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>.
Then you should be able to get json string from event.getBody(), you can either deserialize the json string or directly parse it. For response you need to construct APIGatewayProxyResponseEvent object.
Fixed it using Map<String, String> as input parameter's type.
The JSON in response's body got translated to key-value pairs.
I would like to make the endpoint of the URL in that method a variable one:
public User fetchUser() throws IOException {
URL url = new URL("https://api.github.com/users/octocat");
InputStreamReader reader = new InputStreamReader(url.openStream());
User user = new Gson().fromJson(reader, User.class);
if (user == null) {
logger.error("Could not return desired output.");
return null;
} else {
logger.info("The output returned.");
return user;
}
}
Modifying it to this does not solve the case (changed 'octocat' into '{endPoint}'):
public User fetchUser(#PathVariable String endPoint) throws IOException {
URL url = new URL("https://api.github.com/users/{endPoint}");
This is the GET method from my RestController:
#GetMapping("/user/info/{login}")
public User getUser(#PathVariable String login) throws IOException {
return userService.fetchUser();
}
The browser returns this message:
There was an unexpected error (type=Internal Server Error, status=500).
https://api.github.com/users/{endPoint}
Also, if I modify my URL to this:
URL url = new URL("https://api.github.com/users");
Then the response is this:
There was an unexpected error (type=Internal Server Error, status=500).
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
Help, please.
For your first exception, you could try using string concatenation to append the endpoint to the URL and see if the connection opens that way:
URL url = new URL("https://api.github.com/users/" + endpoint);
For your second exception, it looks like you're telling GSON you have an object of type User when you actually have an array of some sort. You may have to change the Type parameter in fromJson() so that gson can deserialize the json properly. Here is an example of deserializing arrays in gson.
Since I see you're using spring-web and this looks like a RESTful API, I would also suggest configuring a RestTemplate Bean and injecting it into your service to make the request out to github rather than using java.net.url. You can find a nice guide on spring.io for how that works.
I have the following structures defined in thrift.
struct ResponseBody {
1: binary payload
2: string text
}
struct Response {
1: string header
2: ResponseBody body
}
When i try to deserialize to Response class, I am getting following exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Conflicting setter definitions for property "payload": com.project.thrift.kaushik.ResponseBody#setPayload(1 params) vs com.project.thrift.kaushik.ResponseBody#setPayload(1 params)
Since thrift is generating two setters in generated java file
setPayload(byte[] payload) and setPayload(ByteBuffer payload)
I tried with Jackson 2.9
Json.decodeValue(response, Response.class)
I am working on a jersey - java project where I have to get the json data in string format and parse each data separately. I am able to get the response in string using post method. When I try to use JSON lib to parse the string data class not found exception is produced. I want the returned string to be split up. Below is my json.
{
"startdate": "11/11/11",
"enddate": "12/12/12",
"operation_name": "task1",
"user_id": "user1",
"operation_key": ["KKMM-025", "SFF-025", "TTR-022"]
}
Resource method
#POST
#Path("OpertaionDetails")
#Consumes({MediaType.APPLICATION_JSON , MediaType.APPLICATION_XML})
public Response CreateOperations(String incoming_data) throws Exception
{
try
{
JSONParser parse = new JSONParser(); // class not found exceptin i have added the lib properly its working fine when it is used in main method of java.
JSONObject jobj = (JSONObject)parse.parse(incoming_data);
JSONObject Jstart_date = (JSONObject) jobj.get("startdate");
// this data to be paresed
System.out.print("incomingData"+incoming_data);
}
catch(Exception e)
{
e.printStackTrace();
}
return Response.ok(incoming_data).build();
}
#POST
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
#Path("/data/services")
public Response DiscoverDevice(BlockDevsPost blockdevice) {
for (DeviceIdentifier device : blockdevice.getDevice()) {
String dev = device.Device();
System.out.println("DEVICE "+ dev);
if (dev == null || dev.equals("")){
return Response.status(Response.Status.BAD_REQUEST).entity("Device cannot be null or empty.").build();
}
}
}
Getting this error when fired POST from REST Client when dev is null. I am not able to get JSON and this error is thrown:
Unexpected character (D) at position 0. Device Identifier cannot be null or empty.
Where D in Device Identifier marked as Red which means it is not returning JSON as response.
Your client is expecting to get JSON but you have set a plain string in the Response entity and application/json as content-type. You need to return a valid JSON. For example
return Response
.status(Response.Status.BAD_REQUEST)
.entity("{\"error\":\"Device cannot be null or empty.\"}")
.build();
You can also build the json response string using your preferred mapper (you will need to add a dependency). This is an example using Jackson
Jackson using API
ObjectMapper mapper = new ObjectMapper();
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("error", "Device cannot be null or empty.");
String json = mapper.writeValueAsString(objectNode);
Jackson using POJO
class ErrorBean{
private String error;
//getters and setters
}
ObjectMapper mapper = new ObjectMapper();
ErrorBeanerrorBean = new ErrorBean();
errorBean.setError ("Device cannot be null or empty.");
String json = mapper.writeValueAsString(errorBean);
You can also return POJO from your service method and let the JAX-RS implementation to convert them to JSON (this means change the response type). See https://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/