Spring HATEOAS embedded resource support

前端 未结 8 869
别那么骄傲
别那么骄傲 2020-12-07 14:12

I want to use the HAL format for my REST API to include embedded resources. I\'m using Spring HATEOAS for my APIs and Spring HATEOAS seems to support embedded resources; how

相关标签:
8条回答
  • 2020-12-07 14:45

    Pre HATEOAS 1.0.0M1: I couldn't find an official way to do this...here's what we did

    public abstract class HALResource extends ResourceSupport {
    
        private final Map<String, ResourceSupport> embedded = new HashMap<String, ResourceSupport>();
    
        @JsonInclude(Include.NON_EMPTY)
        @JsonProperty("_embedded")
        public Map<String, ResourceSupport> getEmbeddedResources() {
            return embedded;
        }
    
        public void embedResource(String relationship, ResourceSupport resource) {
    
            embedded.put(relationship, resource);
        }  
    }
    

    then made our resources extend HALResource

    UPDATE: in HATEOAS 1.0.0M1 the EntityModel (and really anything extending RepresentationalModel) this is natively supported now as long as the embedded resource is exposed via a getContent (or however you make jackson serialize a content property). like:

        public class Result extends RepresentationalModel<Result> {
            private final List<Object> content;
    
            public Result(
    
                List<Object> content
            ){
    
                this.content = content;
            }
    
            public List<Object> getContent() {
                return content;
            }
        };
    
        EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
        List<Object> elements = new ArrayList<>();
    
        elements.add(wrappers.wrap(new Product("Product1a"), LinkRelation.of("all")));
        elements.add(wrappers.wrap(new Product("Product2a"), LinkRelation.of("purchased")));
        elements.add(wrappers.wrap(new Product("Product1b"), LinkRelation.of("all")));
    
        return new Result(elements);
    
    

    you'll get

    {
     _embedded: {
       purchased: {
        name: "Product2a"
       },
      all: [
       {
        name: "Product1a"
       },
       {
        name: "Product1b"
       }
      ]
     }
    }
    
    0 讨论(0)
  • 2020-12-07 14:47

    here is a small example what we've found. First of all we use spring-hateoas-0.16

    Imaging we have GET /profile that should return user profile with embedded emails list.

    We have email resource.

    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    @Relation(value = "email", collectionRelation = "emails")
    public class EmailResource {
        private final String email;
        private final String type;
    }
    

    two emails that we want to embedded into profile response

    Resource primary = new Resource(new Email("neo@matrix.net", "primary"));
    Resource home = new Resource(new Email("t.anderson@matrix.net", "home"));
    

    To indicate that these resources are embedded we need an instance of EmbeddedWrappers:

    import org.springframework.hateoas.core.EmbeddedWrappers
    EmbeddedWrappers wrappers = new EmbeddedWrappers(true);
    

    With the help of wrappers we can create EmbeddedWrapper instance for each email and put them into a list.

    List<EmbeddedWrapper> embeddeds = Arrays.asList(wrappers.wrap(primary), wrappers.wrap(home))
    

    The only thing is left to do is to construct our profile resource with these embeddeds. In the example below I use lombok to short the code.

    @Data
    @Relation(value = "profile")
    public class ProfileResource {
        private final String firstName;
        private final String lastName;
        @JsonUnwrapped
        private final Resources<EmbeddedWrapper> embeddeds;
    }
    

    Keep in mind annotation @JsonUnwrapped on embeddeds field

    And we are ready to return all this from controller

    ...
    Resources<EmbeddedWrapper> embeddedEmails = new Resources(embeddeds, linkTo(EmailAddressController.class).withSelfRel());
    return ResponseEntity.ok(new Resource(new ProfileResource("Thomas", "Anderson", embeddedEmails), linkTo(ProfileController.class).withSelfRel()));
    }
    

    Now in the response we'll have

    {
    "firstName": "Thomas",
    "lastName": "Anderson",
    "_links": {
        "self": {
            "href": "http://localhost:8080/profile"
        }
    },
    "_embedded": {
        "emails": [
            {
                "email": "neo@matrix.net",
                "type": "primary"
            },
            {
                "email": "t.anderson@matrix.net",
                "type": "home"
            }
        ]
    }
    }
    

    Interesting part in using Resources<EmbeddedWrapper> embeddeds is that you can put different resources in it and it will automatically group them by relations. For this we use annotation @Relation from org.springframework.hateoas.core package.

    Also there is a good article about embedded resources in HAL

    0 讨论(0)
提交回复
热议问题