toedter / spring-hateoas-jsonapi

A JSON:API media type implementation for Spring HATEOAS
Apache License 2.0
106 stars 15 forks source link

jsonApiModelBuilder won't add a relationship to modelbuilder #71

Closed emoleumassi closed 1 year ago

emoleumassi commented 1 year ago
final JsonApiModelBuilder jsonApiModel = jsonApiModel()
               .model(modelObject)
               .link(linkTo(methodOn(SomeController.class).findOne(id)).withSelfRel());
      if (condition) {
         List<ModelObject> values =repository(ids)
                                                      .stream()
                                                      .map(ModelObject::new).collect(Collectors.toList());
         jsonApiModel.relationship("key", values);
      }
      EntityModel entityModel = EntityModel.of(jsonApiModel.build());
      return new ResponseEntity<>(entityModel, HttpStatus.OK);

i get the object but without the relationship. There are no relationship in responseEntity body but the values have some values.

I use:

implementation 'com.toedter:spring-hateoas-jsonapi:1.6.0'
implementation 'org.springframework.boot:spring-boot-starter-hateoas:2.7.8'
toedter commented 1 year ago

If you create an EntityModel of an JsonApiModel, all JSON:API specific things are lost, since EntityModel don't support them.

When working with JsonApiModels, your methods have to return ResponseEntity<RepresentationModel<?>>, like

final RepresentationModel<?> yourModel = jsonApiModelBuilder.build();
return ResponseEntity.ok(yourModel);
emoleumassi commented 1 year ago

i changed the response type to ResponseEntity<RepresentationModel<?>> but i have the same issue

toedter commented 1 year ago

Could you paste the whole method or provide a link to your code? Then I can take a look.

emoleumassi commented 1 year ago
@GetMapping("/path/{id}")
   public ResponseEntity<RepresentationModel<?>> findOne(@PathVariable String id,
                                                            @RequestParam(name = "condition", required = false) boolean condition)
   {
      Object object = repository.findById(id);
      if (object== null) {
         throw new ResourceNotFoundException("Could not resolve object for : " + id);
      }

     final JsonApiModelBuilder jsonApiModel = jsonApiModel()
               .model(modelObject)
               .link(linkTo(methodOn(ThisController.class).findOne(id)).withSelfRel());
      if (condition) {
         List<AnotherObject> values =repository(ids)
                                                      .stream()
                                                      .map(AnotherObject::new).collect(Collectors.toList());
         jsonApiModel.relationship("key", values);
      }
     final RepresentationModel<?> yourModel = jsonApiModel.build();
     return ResponseEntity.ok(yourModel);
}

i send http://localhost:8080/path/123456?condition=true

toedter commented 1 year ago

Hm, as long as your AnotherObjects have something that could be mapped to a JSON:API resource id (e.g. a field named id), it should work. Could you please paste the Class AnotherObject.

emoleumassi commented 1 year ago
@Getter
@Setter
@NoArgsConstructor
public class AnotherObject extends RepresentationModel<AnotherObject>
{
   @JsonApiId
   private String id;
   @JsonApiType
   private final String type = "anotherObject";

  // other attributes and constructor
toedter commented 1 year ago

You could delete the @JsonApiId annotation here (you only need it for fields that have another name than id).

But if all objects have a valid id set, it should work. Just for testing, try

@JsonApiId
private String id = "1";
emoleumassi commented 1 year ago

i have it now the responseEntity. Don't ask me how, but it works. I didn't change anything

i use:

implementation 'org.springframework.data:spring-data-rest-webmvc:3.7.6'
    implementation 'org.springdoc:springdoc-openapi-hateoas:1.6.14'
    implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'

When i use RepresentationModel<?> i don't have a wrong representation in swagger. Also when i use RepresentationModel<? extends Object>. But when i use a EntityModel i have a correct representation. It is reason why i prefer to use EntityModel. There are some issue with swagger and representationModel?

With representationModel, i have this description in swagger:

{
  "_links": {
    "additionalProp1": {
      "href": "string",
      "hreflang": "string",
      "title": "string",
      "type": "string",
      "deprecation": "string",
      "profile": "string",
      "name": "string",
      "templated": true
    },
    "additionalProp2": {
      "href": "string",
      "hreflang": "string",
      "title": "string",
      "type": "string",
      "deprecation": "string",
      "profile": "string",
      "name": "string",
      "templated": true
    },
    "additionalProp3": {
      "href": "string",
      "hreflang": "string",
      "title": "string",
      "type": "string",
      "deprecation": "string",
      "profile": "string",
      "name": "string",
      "templated": true
    }
  }
}
toedter commented 1 year ago

Yes, this is a drawback when you want to use the Swagger API. I use Spring REST Docs and ePages (https://github.com/ePages-de/restdocs-api-spec) for generating OpenAPI 3 yml files with JSON:API exanmples/schemas.

Rezar00 commented 1 year ago

Hi @toedter I am using spring boot 3.1.1 and also implementation 'org.springdoc:springdoc-openapi-ui:2.0.5'

I wrapped the request model with EntityModel and consume "application/vnd.api+json" in rest endpoint.

But on the swagger page, I cannot see the correct representation.