Is there a way I can simplify this:
#PostMapping(value = "create", consumes = "application/json", produces = "application/json")
public Response create(#RequestBody ObjectNode json) {
return new Response(json.get("name").asText(), 200);
}
Mainly I wonder if it's possible to annotate consumes & produces. My app will be an API service so all requests/responses will be JSON based. I don't want to keep that over each controller method.
Less important:
I know I can pass #RequestParam Comment comment if this is a method to create a comment but what if I want to create a comment and something else at the same time from the same method.
Is there a cleaner way than doing ObjectNode and json and than json.get().as...
As it turns out you can annotate your methods/controllers with #ResponseBody and #RequestBody to achieve the same result.
MyServer.class
#POST
public Response save(String data) {
return Response.status(Response.Status.ACCEPTED).entity(repository.save(data)).build();
}
Now it will go to the server as post request.
if no id present, so add this code.
ResourceConverter converter = new ...
converter.disableDeserialisationOption(DeserializationFeature.REQUIRE_RESOURCE_ID);
This allows you to remove id restriction.
Alternative is that you should use current snapshot version
Here is the save method from the repository class
public String save(String data) {
Server myServer= converter.readObject(data.getBytes(), Server.class);
Key<Server> savedMyServer = datastore.save(myServer);
Server usingKey = datastore.getByKey(Server.class, savedMyServer);
try {
return new String(converter.writeObject(usingKey), StandardCharsets.UTF_8);
} catch (JsonProcessingException | IllegalAccessException e) {
LOGGER.debug(e.getMessage());
}
return null;
}
Related
i would like to implement an exception handler for restful api if the uri is not matched.
For example: url is
localhost:8080\test\generateNumber will return
{"response_code":"200"}
andif the url is wrong for example:
localhost:8080\test\generateNumber2 will return
{"response_code":"404","message":"uri not found"}
i have no idea on how to do it. Can someone help?
I presume you're using Spring?
In that case you can use #ExceptionHandler like this:
#RestController
public class Example1Controller {
#GetMapping(value = "/testExceptionHandler", produces = APPLICATION_JSON_VALUE)
public Response testExceptionHandler(#RequestParam(required = false, defaultValue = "false") boolean exception)
throws BusinessException {
if (exception) {
throw new BusinessException("BusinessException in testExceptionHandler");
}
return new Response("OK");
}
#ExceptionHandler(BusinessException.class)
public Response handleException(BusinessException e) {
return new Response(e.getMessage());
}
}
And get a message in response.
More - in this manual.
I want to use OKHttp3-based RestTemplate to remotely call the interface queryByIds to get basic user information.
#Configuration
public class CloudConfig {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
}
the implementing method queryByIds is below:
#GetMapping("/queryByIds")
public GraceJSONResult queryByIds(#RequestParam String userIds) {
if (StringUtils.isBlank(userIds)) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
}
List<String> userIdList = JsonUtils.jsonToList(userIds, String.class);
ArrayList<AppUserVO> userVOList = new ArrayList<>();
assert userIdList != null;
userIdList.forEach(id -> {
AppUserVO userInfo = getBasicUserInfo(id);
userVOList.add(userInfo);
});
return GraceJSONResult.ok(userVOList);
}
Here is the bussiness code, the http://user.mootalk.com is switched to localhost using SwitchHosts:
// Get the basic information of each user and put it in userVOList
String userServerUrlExecute = "http://user.mootalk.com:8003/user/queryByIds?userIds=" + JsonUtils.objectToJson(publisherIdSet);
System.out.println(userServerUrlExecute);
// the debugger paused
ResponseEntity<GraceJSONResult> entity =
restTemplate.getForEntity(userServerUrlExecute, GraceJSONResult.class);
Here is my util class:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
/**
* json converter
*/
public class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
When I debug the code ,it didn't go into the queryByIds method, and the console printed the userServerUrlExecute below:
But if you construct a request in Postman like this:
http://user.mootalk.com:8003/user/queryByIds?userIds=210726G71HSY2YY8, it could go into the queryByIds method but the userIdList turned out to be null.
If you construct a request in Postman like this :
http://user.mootalk.com:8003/user/queryByIds?userIds=[\"210726G71HSY2YY8\",\"200628AFYM7AGWPH\"],it works well.
So what's wrong with my code while passing the param?
Later message1:
Now the last construct request did't go into queryByIds both in Chrome's address bar and Postman, it threw a 400 Bad Request;
I replaced #RequestParam with #RequestBody in queryByIds, it still threw a 400 Bad Request
Latter message2:
Now it works...with the same code. This is really a mystery.
Really I wouldn't just pass in JSON into a query parameter like you are doing, it's nasty and doesn't really follow any sort of RESTFUL API standard.
You have 4 options as I see it:
Change to a HTTP POST request and pass in the JSON Data into the request body (Recommend and follows best practise).
If for whatever reasons your requirements are it needs to be a HTTP GET request and needs to be a query parameter then you need to base64 encode the JSON before passing it in.
?userIds=W1wiMjEwNzI2RzcxSFNZMllZOFwiLFwiMjAwNjI4QUZZTTdBR1dQSFwiXQ==
Again if it has to be a HTTP GET request but it doesn't need to be JSON then I would do a comma separated list of IDs into the query parameter
?userIds=210726G71HSY2YY8,200628AFYM7AGWPH
Just request 1 user id at a time.
Your requirements are probably going to be what determines the approach you take.
I wish to code the Rest Controller in spring-boot for my webhook. I am creating a google action, with simple actions.
This is a boilerplate: https://github.com/actions-on-google/dialogflow-webhook-boilerplate-java/blob/master/src/main/java/com/example/ActionsServlet.java.
I want to do the same, only in spring-boot. I want to manipulate JSON body as input, but not sure how to do this.
#RestController
public class indexController extends HttpServlet {
#Autowired
private App actionsApp;
//handle all incoming requests to URI "/"
// #GetMapping("/")
// public String sayHello() {
// return "Hi there, this is a Spring Boot application";}
private static final Logger LOG = LoggerFactory.getLogger(MyActionsApp.class);
//handles post requests at URI /googleservice
#PostMapping(path = "/", consumes = "application/json", produces = "application/json")
public ResponseEntity<String> getPost(#RequestBody String payload,
#RequestHeader String header, HttpServletResponse response) throws IOException {
//Not sure what to do here.
System.out.println(jsonData);
return ResponseEntity.ok(HttpStatus.OK);
try {
//writeResponse(response, jsonResponse);
//String med request body og object that has all request header entries
String jsonResponse = actionsApp.handleRequest(body, listAllHeaders(header)).get();
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
} catch (
InterruptedException e) {
System.out.println("Something wrong happened, interupted");
} catch (
ExecutionException e) {
System.out.println("Something wrong happened, execution error");
}
}
First, there is an error in your code. There might be a wrong "return" before your function logic.
return ResponseEntity.ok(HttpStatus.OK);
Second, as you are using Spring Framework, and you use "#RequestBody String payload" in the method, the Spring Framework will take the request body and set it to payload. If you set payload as a specific type. The framework will deserialize the body to it.
Finally, you can directly use payload in your code. The value of it would be the request body.
If you want to decode the json string. You can use org.json library.
JSONObject obj = new JSONObject(payload);
String name = obj.optString("name");
The code will get the value of name in the json.
Following is my controller
#RestController
#RequestMapping("identity/v1/")
public class InvestigateTargetController {
#RequestMapping(method = RequestMethod.POST, value = "receive",
produces = OneplatformMediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<InvestigateOutputResource>
processRequest(#RequestBody JSONObject jsonObject) {
System.out.println(jsonObject.toString());
return new ResponseEntity<>(HttpStatus.OK);
}
}
I am trying to send a json object to this controller via POSTMAN. But when I print jsonObject.toString() the output is {} ( empty ). Following are snapshots of POSTMAN:
Where am I going wrong ?
Create a java class having properties (with getters and setters) same as json object and put it as requestbody.
Solved it. Instead of JSONObject catch it in a string type.
So I am trying to build a simple REST API and wanted to try out spark but for some reason I can't seem to extract any parameters.
Here is my endpoint for testing this:
post("/hello", (req, res) -> {
String str = req.attribute(":username"); //TODO THIS IS ALWAYS NULL!!!!!!!
System.out.println(str);
System.out.println("BODY IS WORKING:");
System.out.println(req.body().toString());
return "PANNKAKA";
});
Now if I try to make a request at http://localhost:4567/hello with the body {
"username": "bla"
}, the str variable is just null. But if I call on the body method on req, req.body().toString(); it does indeed get the body: {
"username": "bla"
} printed to the console. So the body is coming through.
This is the result in the console window:
null
BODY IS WORKING:
[
{
"username": "bla"
}
]
So how do you extract the parameter from the request's body? I have tried lots of different formatting on the param name but it just doesn't work. Been sitting with this for hours now!
I have looked at the documentation and I believe I do the correct thing:
http://sparkjava.com/documentation.html
I guess there are few ways to do this. Also, you didn't mention it by I'm assuming you send your data formatted as JSON.
I do that using an ObjectMapper (using this package com.fasterxml.jackson.databind.ObjectMapper) and a PayLoad class.
I create a simple class used as the PayLoad. It contains just fields and their getters and setters. for each value you send in the JSON you'll create the corresponding field, with exactly the same name In your case you'll have a field called username), and then the object mapper maps the JSON that you sent from the client to this class pattern. Example:
public class UserPayload {
private long id;
private String username;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Then I parse the request body into this payload using the object mapper:
class SomeClass {
...
private static Object postUser(Request req, Response res) throws JSONException {
ObjectMapper mapper = new ObjectMapper();
UserPayload pl = null;
try {
pl = mapper.readValue(req.body(), UserPayload.class); // <------
} catch (JsonMappingException e1) {
...
} catch (Exception e2) {
...
}
System.out.println(pl.getUsername() + " " + pl.getId());
...
}
}
And of course register your route:
post("/hello", SomeClass::postUser);
Hope it helps.
If someone uses a simpler way, I'll be happy to hear.
You should have declared your route like the following, with the parameter :username as part of the route name:
post("/hello/:username", (req, res) -> {
String str = req.attribute(":username"); //TODO THIS IS ALWAYS NULL!!!!!!!
System.out.println(str);
System.out.println("BODY IS WORKING:");
System.out.println(req.body().toString());
return "PANNKAKA";
});
or, if what you wanted is to deal with query parameters, just take a look at this answer.
as Laercio said, if you want to get the value of this line
String str = req.attribute(":username"); //TODO THIS IS ALWAYS NULL!!!!!!!
you should declare the same var as part of your URI
post("/hello/:username" ...) ...
but if you are trying to send a JSON as Content-Type: application/json you won't get the params by that way, this only works if your send the value as Content-Type: application/x-www-form-urlencoded and then your can use req.params("username") this last is the way that ordinary HTML form send the data
Java doesn't handle very well JSON by default, you need to do some tricks to do that, or even better use Gson
If you don't want to use Gson, so you need to read the body line per line and handle by your own that data sent by application/json to get the data.