3

I'm currently working on a small REST web service using spring-data-rest using :

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

I followed the following guide: https://spring.io/guides/gs/accessing-mongodb-data-rest/ and it's working really fine.

I add some annotation on my Person.class, in order to validate the object during a POST request (like @NonNull and so on) like this :

public class Person {

    @Id
    private String id;

    @NonNull
    private String firstName;

    @NonNull
    private String lastName;

    private Integer age;

}

But now I want to do a PATCH request to update my object (by doing a request curl -X PATCH http://localhost:8080/people/598c2a80d8425fae64161cc4 -d '{"age":23}').

It's also working fine, but I want to prevent the update on some fields, people shouldn't be allowed to update firstName and lastName for example.

Is there some way to do it easily with an annotation? Or do I have to do a custom validation for every PATCH (or PUT) request? I don't like that solution because I would have to do it for every entity of my model.

I hope I clearly exposed my problem, if it's not clear, feel free to ask me more questions.

Thanks for your help.

Chinmay jain
  • 979
  • 1
  • 9
  • 20
PurplePanda
  • 258
  • 4
  • 16
  • have a look at this. https://stackoverflow.com/questions/45668388/spring-security-for-certain-entity-variables?noredirect=1#comment78324306_45668388 – ArslanAnjum Sep 12 '17 at 16:14

2 Answers2

1

You could use:

@Column(updatable = false)
@NonNull
private String firstName;

This won't throw errors but will avoid the field from being updated.

Ivo Udelsmann
  • 142
  • 1
  • 13
1

You could override the specific PATCH endpoint and retain only the allowed fields


    @PatchMapping("/persons/{id}")
    HttpEntity<?> patchPerson(@PathVariable("id") Person person,
                            @RequestBody final ObjectNode patch,
                            PersistentEntityResourceAssembler assembler) {
        List<String> allowedFields = List.of("age");
        ObjectNode validPatch = patch.retain(allowedFields);
        Person patchedPerson = jsonPatcher.merge(validPatch, person);

        Person entity = personRepository.save(patchedPerson);
        PersistentEntityResource resource = assembler.toFullResource(entity);
        return ResponseEntity.accepted().body(resource);
    }

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.rest.webmvc.json.DomainObjectReader;
import org.springframework.data.rest.webmvc.mapping.Associations;
import org.springframework.stereotype.Component;

/**
 * Utility class mainly for applying patches to domain objects.
 */
@Component
public class JsonPatcher {

    private final DomainObjectReader domainObjectReader;

    private final ObjectMapper objectMapper;

    @Autowired
    public JsonPatcher(PersistentEntities persistentEntities, Associations associations, ObjectMapper objectMapper) {
        this.domainObjectReader = new DomainObjectReader(persistentEntities, associations);
        this.objectMapper = objectMapper;
    }

    /*
    Almost the same exact implementation used in {@link org.springframework.data.rest.webmvc.config.JsonPatchHandler}
    to merge JSON documents for Spring Data REST. It's copied here because the patch code that Spring uses was made
    internal to the framework.
     */
    public <T> T merge(ObjectNode patch, T target) {
        return domainObjectReader.merge(patch, target, objectMapper);
    }

}
alegria
  • 1,290
  • 14
  • 23