lagoshny / ngx-hal-client

Spring HAL client for Angular
21 stars 15 forks source link

Creating a Resource with an embedded relation fails #52

Open cypressious opened 3 years ago

cypressious commented 3 years ago

I have a Spring Data Rest project with an entity with a @ManyToOne relation to another entity

@Entity
class Foo(
    var id: Long? = null,

    @ManyToOne
    var bar: Bar
)

@Entity
class Bar(
    var id: Long? = null,
    var name: String
)

I would like the bar property to be non-nullable, so it needs to be provided when creating.

This can be achieved using the following request:

POST localhost:8080/foos

{
    "bar": {
        "id:": 1,
        "name": "Baz"
    }
}

Now I would like to do the same using the client.

If I model Foo as follows

export class Foo extends Resource {
    bar: Bar;
}

export class Bar extends Resource {
    id: number;
    name: string;
}

and call

const foo = new Foo();
foo.bar = bar;

fooService.create(foo).subscribe();

I'm getting an HTTP 400 from the API. Inspecting the request shows that it was transformed to the following:

POST localhost:8080/foos

{
    "bar": "http://localhost:8080/bars/1"
}

If I understand correctly, the library transforms properties of the request which are Resources.

I'm able to do the following workaround which feels very dirty but works:

fooService.create({
    bar: { id: bar.id, name: bar.name }
} as any).subscribe();

Is there a cleaner way to do this? If not, consider this a feature request to support creating Resources with embedded relations.

lagoshny commented 3 years ago

Hi @cypressious,

Can you provide some information:

1) When you create a foo

const foo = new Foo();
foo.bar = bar;
fooService.create(foo).subscribe();

A bar resource already created on the server-side or it is a newly created client-side object?

2) When you perform POST request like that:

POST localhost:8080/foos
{
    "bar": {
        "id:": 1,
        "name": "Baz"
    }
}

Do you use custom FooController to handle requests with an embedded resource?

cypressious commented 3 years ago

@lagoshny

  1. The bar resource already exists on the server-side.
  2. No custom controller is used.
lagoshny commented 3 years ago

@cypressious, If you use Spring Data Rest, then

POST localhost:8080/foos

{
    "bar": "http://localhost:8080/bars/1"
}

Should resolve this on the server-side to existing bar resource.

I can't reproduce HTTP 400 with this request from your example in the first post.

Can you provide a detailed example to reproduce this behavior?

Tqup3 commented 3 years ago

Hi @cypressious : Do you have a Spring Data Rest repository for the Bar entity ? I think you don't have one, it's why you can POST :

{
    "bar": {
        "id:": 1,
        "name": "Baz"
    }
}

So if you don't have one on Java side, I don't test locally but I think the Typescript Bar class should not be a "Resource".

@lagoshny : I just discovered your package and tested it fastly, it seems awesome :)

cypressious commented 3 years ago

I have repositories for both entities and they're both annotated with @RestResource