How to set Attribute in postman - java

I using postman and spring boot. In spring boot i using code look like :
public PersistableCategory createCategory(#RequestBody PersistableCategory persistableCategory, MerchantStore store, HttpServletRequest httpRequest) {
MerchantStore merchantStore = (MerchantStore) httpRequest.getAttribute("MERCHANT_STORE");
return categoryService.saveCategories(store,persistableCategory);
}
get attribute from httpservletrequest. But i can't know where i set attribute with name MERCHANT_STORE in postman. I set in body look like
{
"attributes": {
"MERCHANT_STORE": {
"code":"1"
}
},
but it not working. How to set attribute in postman and using HttpServletRequest get it.

if you have more APIs, and need to response like the request (more than one depth attribute)
{
"attributes": {
"MERCHANT_STORE": {
"code":"1",
"code2":{
"element1":"1",
"element2":"2"
}}}
2.First, make a class for response.
public class responseData {
private merchant_store;
// getter, setter, the other elements..
}
i think that's better to make to make class for setting results.
public class result{
private View json; // this object from spring servlet lib.
// and make methods to parse http header(yep, in postman) and to return datas.
}
Let's make response in controller.
public PersistableCategory createCategory(){
MerchantStore merchantStore = (MerchantStore);
httpRequest.getAttribute("MERCHANT_STORE");
Object purpose = categoryService.saveCategories(store,persistableCategory);
Object responseData = new responseData();
responseData.set(purpose);
result.set(responseData, successYn);
return result;
}
Well, successYn is just String in my
Because i wanted to know whether it finished to access DB and set Datas.
if you want you can set other types.

Related

I am trying to create an API using SpringBoot but I don't know how to handle json request/response

I am new to Java and Spring boot. I am creating a new API.
Using postman I am sending a request body which contains request header and request payload.
Then I have a controller which handles the request with the help of RequestPayload class. (And a service and dao file but I am sure those are ok.)
Kindly let me know what Am I missing here or what do I not know.
public class RequestPayload {
String pol_pkg_prod_code;
JSONObject checklist;
public JSONObject getCheckList() {
return checklist;
}
public void setCheckList(JSONObject checklist) {
this.checklist = checklist;
}
public String pol_pkg_prod_code() {
return pol_pkg_prod_code;
}
public void setpol_pkg_prod_code(String pol_pkg_prod_code) {
this.pol_pkg_prod_code = pol_pkg_prod_code;
}
You need a POJO class that will match the structure of your JSON payload, actually a few nested classes. Spring will automatically parse JSON into this POJO.
public class Request {
private RequestPayload reqPayload;
// Getter Setter
}
public class RequestPayload {
private Checklist checklist;
// Getter Setter
}
public class Checklist {
#JsonProperty("pol_pkg_prod_code")
private String polPkgProdCode;
}
Then add it to Controller as an argument like this:
#RequestBody Request request
This tutorial explains it well
https://www.baeldung.com/spring-request-response-body

How to get Authorization header from an MethodInterpcetor on micronaut?

Before everything I tried this two solution but didn't work for me
Equivalent of javax.ws.rs NameBinding in Micronaut?
https://blogs.ashrithgn.com/custom-annotation-to-handle-authorisation-in-micronaut-aop-tutorial/
In my application I have to get a string in the Authorization header and then decode it from base64 and the json transform it into a POJO. Certainly the string is a jwt and I need to decode the public part of the json to get a data from a field.
Technically speaking a client will forward the header to me to take it, decode it and extract the data. (It's very bad practice but that's what I have to do).
For this I am using micronaut 2.4.1 and this is my code:
Interceptor:
public class HeadInterceptor implements MethodInterceptor<Object, Object> {
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
Request request = (Request) context.getParameterValueMap().get("request");
// Where do i get Authorization header?
// i.e String token = (String) context.getParameterValueMap().get("Authorization");
String token = "eyJhdWQiOiJ0ZXN0IiwiaXNzIjoidGVzdCIsInN1YiI6InRlc3QiLCJleHAiOjExMTExMTEsImlhdCI6MTExMTExMTEsImRhdGEiOiJ0ZXN0In0=";
ObjectMapper mapper = new ObjectMapper();
Info info = mapper.readValue(new String(Base64.getDecoder().decode(token)), Info.class);
request.setData(info.getSub().toUpperCase());
return context.proceed();
}
}
Controller:
#Controller("/main")
public class MainController {
#Post
#Head
public Single<Response> index(#Body #Valid Request request) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
}
Here's a sample app https://github.com/j1cs/micronaut-jacksonxml-error
(ignore the name is for other issue)
In your implementation, the header cannot be shown in the interceptor because your index method doesn't receive it as a parameter.
So, if you add it as a parameter as below:
...
#Post
#Head
public Single<Response> index(#Body #Valid Request request, #Header("Authorization") String authorizationHeader) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
...
Then, you can retrieve it in the intercept method via getParameterValues(). Basically, it will be the second argument.
...
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
...
String token = (String) context.getParameterValues()[1];
...
}
...
Update
Since you want your Request to contain both body and header, I edited the solution a bit. Basically, the header is added as a member variable to Request as below:
public class Request {
#NotNull
#NotBlank
private String info;
private String data;
#Header("Authorization")
String authorizationHeader;
}
Then, use #RequestBean rather than a #Body annotation on your Request parameter:
...
#Post
#Head
public Single<Response> index(#RequestBean #Valid Request request) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
...
Finally, you can access the header easily in your intercept() method as follows:
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
...
Request request = (Request) context.getParameterValueMap().get("request");
String token = request.authorizationHeader;
...
}
I created a pull request for this change here, so you can check how it works.
In order to address the problem, you may first break the problem into parts.
Part 1: How to get arbitrary header (or list all headers)?
Try to use request.getHeaders() doc.
Part 2: How to get the header named Authorization ?
Use the way in part 1. In addition, be careful about the case. For example, is Authorization the same as authorization?
Method 2:
In controller (https://github.com/j1cs/micronaut-jacksonxml-error/blob/master/src/main/java/me/jics/MainController.java):
public Single<Response> index(#Body Request request, #Header('Authorization') String authorization) {
...
}
p.s. the "Header" annotation's doc is here: https://docs.micronaut.io/2.0.1/api/io/micronaut/http/annotation/Header.html
In interceptor:
...
String token = context.getParameterValueMap().get("authorization");
...
Why the code looks like this:
Firstly get the auth header you want using parameter injection.
Secondly, recall the fundamental concepts of AOP / AspectJ (which your interceptor class uses). Inside your interceptor, you intercept a method (in your case, the index method in controller. Thus, you can happily get the parameters of that method. In the code above, just the authorization parameter.
Please tell me if you are stuck on somewhere (and paste the code and the outputs).

Custom response on bad request using spring RestController

I have the following controller. I am using Spring to create Restful APIs.
#RestController
public class UserController extends RestControlValidator {
#RequestMapping(value = "/user/", method = RequestMethod.POST, headers = "Accept=application/json", consumes = "application/json", produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody List newUser(#RequestBody #Valid UserInput input,BindingResult result)
{Some code}
}
The UserInput class looks like this:
public class UserInput{
#NotEmpty
private String emailId;
#NotEmpty
private String fName;
private String lName;
private int sex;
//getters and setters
Now when I try and access /user/ with data {"sex":"Male"}, I get the following response:
I want the response in case of such a request to be:
{"errors":{"sex":"The value must be an integer"}}
Is there any way of customising BAD REQUEST responses in Spring?
Considering the current scenario the most ideal solution would be to alter the behavior of HandlerMethodArgumentResolve as the json to pojo constructed by #RequestBody fails because we dont get a chance to check the wrong data and this check can very well be done in the custom message converter
A. first we would need to create LanguageMessageConverter as follows
public class LanguageMessageConverter extends
AbstractHttpMessageConverter<Language> {
private Gson gson = new Gson();
public LanguageMessageConverter() {
super(new MediaType("application", "json", Charset.forName("UTF-8")));
}
#Override
protected boolean supports(Class<?> clazz) {
return Language.class.equals(clazz);
}
Map<String, String> mp = new HashMap<>();
#Override
protected Language readInternal(Class<? extends Language> clazz,
HttpInputMessage httpInputMessage) throws IOException,
HttpMessageNotReadableException {
Map langmp = gson.fromJson(
convertStreamToString(httpInputMessage.getBody()), Map.class);
for (Field field : clazz.getDeclaredFields()) {
if (!langmp.get(field.getName()).getClass().getCanonicalName().equals(field.getType().getCanonicalName())) {
if (field.getType().getCanonicalName().equals("java.lang.Integer")||field.getType().getCanonicalName().toString().equals("int")) {
langmp.put(field.getName(), "0");
} else if (field.getType().equals("java.lang.String")) {
//TODO COde needs to be improved here because this check is not efficient
langmp.put(field.getName(), "wrong");
}
}
}
Language lang = gson.fromJson(gson.toJson(langmp), clazz);
return lang;
}
we need to set the media type new MediaType("application", "json", Charset.forName("UTF-8")) which will make sure this class intervenes the mentioned MIME type
Considering we need to manipulate the result I found it best to convert it to map langmp (There are better JSON Parsers which can be used)
Since we need to to understand the existing type I used reflection api to get the fields via getDeclaredFields()
Using the above made the logical check using the datatype to understand if the type is incorrect for eg if the field datatype is int and if it is found as String then corresponding map value will be substituted
once that is done the map will hold the updated values where in if the data was wrong a default value would be set eg if the int var is set to 0 since the originating json had a String in it.
Once that is done the updated map is converted to the concerned class.
B. Secondly we need to register the custom MessageConverter in the dispatcher xml i.e. LanguageMessageConverter
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<bean class="com.comp.org.controller.LanguageMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
register-defaults="true" is very important since we are adding Custom MessageConverter but we also need the other existing converters working along with the one we have added
LanguageMessageConverter needs to be registered here.
C. Considering the concerned pojo is populated with the necessary details it would reach our controller post processing in the custom converter now we would add the manual validation eg. if the int variable has 0 the necessary error json should be returned
As per your request even if the json consists of the wrong data the custom message converter should process it and accordingly in the controller we can validate the condition mentioned.
The code definitely can be improved further. Kindly let me know if this solution fulfilled your requirement or any part of the code requires further elaboration and hopefully addressed your concern.
I had the same issue, than I solved that way:
Create an Object called Error, like that (don't forget to implement Serializable...):
private String fieldName;
private String errorCode;
private String defaultMessage;
public Error() {
}
public Error(String fieldName, String errorCode, String defaultMessage) {
this.fieldName = fieldName;
this.errorCode = errorCode;
this.defaultMessage = defaultMessage;
}
/* getters, setters */
Inside the #RestController method you ave to call inputValidator.validate() method (if you didn't create an Object Validator for your UserInput then we're really don't speaking the same language...)
// validating the userInput
userInputValidator.validate(userInput, bindingResult);
if (bindingResult.hasErrors()) {
List<Error> errors = new ArrayList<>(bindingResult.getErrorCount());
for (FieldError fieldWithError : bindingResult.getFieldErrors()) {
errors.add(new Error(fieldWithError.getField(), fieldWithError.getCode(), fieldWithError.getDefaultMessage()));
}
return errors;
}
// in case of success:
return null;
Finally you'll have to translate the JSON object to your client side. You'll have two kind of objects:
3.1. null (undefined depending on the language you're using)
3.2. A JSON object like that:
[
{
"fieldName": "name",
"errorCode": "user.input.name.in.blank",
"defaultMessage": "Insert a valid name!"
},
{
"fieldName": "firstPhone",
"errorCode": "user.input.first.phone.blank",
"defaultMessage": "Insert a valid first phone!"
}
]

How to access the "findById" method of a RESTful service through "getJSON"?

This is the following code of my RESTful service class:
#RequestScoped
#Path("/empresas")
public class EmpresaEndpoint {
#Inject
private EmpresaRB empresaRB;
#GET
#Path("/{id:[0-9][0-9]*}")
#Produces("application/json")
public Response findById(#PathParam("id") final Long id) {
//TODO: retrieve the empresas
Empresa empresas = null;
if (empresas == null) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok(empresas).build();
}
#GET
#Produces("application/json")
public List<Empresa> listAll(
#QueryParam("start") final Integer startPosition,
#QueryParam("max") final Integer maxResult) {
//TODO: retrieve the empresa
return empresaRB.getEmpresas();
}
}
If I wanted to access all the data stored on "Empresa" via jQuery, I would do:
$.getJSON( "rest/empresas", function( data ) {
//whatever is needed.
}
The code above would access the "listAll" method. So how can I access the "findById" method and pass the necessary parameter?
Assuming you have a variable called empresaId that holds the id for the entity, this should work.
$.getJSON( "rest/empresas/" + empresaId, function(data) {
// Whatever is required here
}
Well without having used that particular framework, it looks like it's mapping to the right method based on the path - it will use findById if the path has an ID, e.g.
$.getJSON("rest/empresas/100", function(data) {
// ...
}
(That will find the item with ID 100... obviously substitute the ID of the item you want to find. We don't know where that's coming from, but "rest/empresas/" + id may well be all you need.)
In my initial code, there was no query being connected to the variable "empresa", on the method findById().
I created a query on the repository class and assigned it to the variable. Problem Solved.
Thank you all for the time lended.

Play Framework 2: How to correctly construct objects from various sources in the controller and then validate them?

For this example, the user wishes to create a blog post for their site. Form submission is handled through AJAX. The POST request is handled by the createPost method in the controller. The method extracts the json data and combines it with the users session data to construct the appropriate Post object. It then validates the data and returns an appropriate response.
The Post model is as follows:
#Entity
public Post extends model {
#Id
public Long id;
#Required
public User author;
#Required
public String title;
#Required
public String body;
}
The controller method is as follows:
#BodyParser.Of(BodyParser.Json.class)
public static Result createPost() {
JsonNode json = request().body().asJson();
Post post = new Post();
post.author = User.findbyId(request().username());
post.title = json.findPath("title").textValue();
post.body = json.findPath("body").textValue();
Form<Post> filledForm = Form.form(Post.class).bind(Json.toJson(post));
if (filledForm.hasErrors())
return badRequest(filledForm.errorsAsJson());
// save post
return ok();
}
Now, this method works, however, there must be a better way of doing it rather than taking the json request, extracting it into an object and then converting that object back into json so that it can be bound to the form. Any ideas?
The common way to do it is using bindFromRequest in the controller side.
public static Result savePost() {
Form<Post> postForm= form(Post .class).bindFromRequest();
if(postForm.hasErrors()) {
Logger.error("Form has errors: " + postForm.errorsAsJson());
return badRequest(filledForm.render(postForm));
}
Post post=postForm.get();
post.save()
....
}
For a full example you can checkout the forms sample.
And the AJAX post could be something like that:
function postUrl(form){
var postData = new FormData($(form)[0])
var formURL = $(form).attr("action");
var request=$.ajax({
url : formURL, type: "POST", data : $(form).serialize(),
});
request.done(function(data) {
//Whatever
});
}
It's a commonly discussed issue in Play that form classes shouldn't really be domain classes. Only works in simple cases.
One alternative is to create a form-data class and bind that. The form-data class can contain data from many different models. Then have code that loads your domain object (Post) a copy fields from form-data object. I use code-generation for the form-data to domain-object code. YMMV.

Categories

Resources