Deleting an association over REST in Spring Data R

2019-05-13 17:43发布

I wish to know how to delete a many-to-many association via a REST call. I am able to create records, and associated them, but do not understand how to delete.

I have a Spring Boot project where i'm using REST and HATEOAS to by pass Services and Controllers and expose my Repository directly.

I have a User Model/Domain class

@Entity
@Table(name = "usr")
public class User implements Serializable {

private static final long serialVersionUID = 1L;

@Version
private long version = 0;

@Id
@GeneratedValue(generator="optimized-sequence")
private Long id;

@Column(nullable = false, unique = true, length = 500)
@Size(max = 500)
private String userName;

@Column(nullable = false, length = 500)
@Size(max = 500)
private String firstName;

@Column(nullable = false, length = 500)
@Size(max = 500)
private String lastName;

@ManyToMany(    fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable( name="user_role",
            joinColumns={ @JoinColumn(  name = "user_id", 
                                        nullable = false
                                    ) 
                        }, 
            inverseJoinColumns={ @JoinColumn(   name="role_id", 
                                                nullable=false
                                            ) 
                                }
)
private Set<Role> roles = new HashSet<Role>(0);

...Getters/Setters Below...

As as you can see, I have a roles member that is Many-To-Many association with Role class, of which the code is such:

@Entity
public class Role {

@Id
@GeneratedValue(generator="optimized-sequence")
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private String description;

...Getters/Setters Below...

My repositories look like so:

UserRepository

public interface UserRepository extends 
        JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

    List<User> findByUserName(String username);

}

RoleRepository

public interface RoleRepository 
        extends JpaRepository<Role, Long> {

}

Now, all is well. When I access the project root from a browser, I get the repository index/directory in JSON+HAL format. Wonderful.

(Note I'm remove the http:// part from the test below because StackOverflow is counting it towards my links quota)

I, using WizTools REST Client, HTTP.POST to the Role ( localhost:8080/resttest/roles ) repository and create a new Role. Success, Role ID #4 created.

Then I POST to the User repository to create a User ( localhost:8080/resttest/users ). Success, User ID #7 created.

Then I PUT to the User repository to create an association with the role:

PUT localhost:8080/resttest/users/7/roles
Content-type: uri-list
Body: localhost:8080/resttest/roles/4

Great! Association made. User 9 is now associated with Role 4.

Now I can't for the life of me figure out how to DELETE this association.

I'm sending an HTTP DELETE instead of PUT with the same command as above.

DELETE localhost:8080/resttest/users/7/roles
Content-type: uri-list
Body: localhost:8080/resttest/roles/4

I get back: HTTP/1.1 405 Method Not Allowed

{
    "timestamp":1424827169981,
    "status":405,
    "error":"Method Not  Allowed",
    "exception": "org.springframework.web.HttpRequestMethodNotSupportedException",
    "message":"Request method 'POST' not supported"
}

2条回答
SAY GOODBYE
2楼-- · 2019-05-13 17:45

From the docs:

DELETE

...

405 Method Not Allowed - if the association is non-optional

PUT means that you replace the whole roles Set. So to remove a single link you PUT all remaining links. If you only have a single link and want to remove it you would PUT an empty collection:

PUT localhost:8080/resttest/users/7/roles
Content-type: uri-list
Body:

BTW: You won't send a body with a DELETE request. It doesn't make sense.

EDIT

See also this answer from the developer of Spring HATEOAS.

查看更多
趁早两清
3楼-- · 2019-05-13 17:55

Although creating a PUT request with remaining elements does the trick, DELETE is an accepted command to delete an association resource and is in most cases easier to use.

As for your example, this should work:

DELETE localhost:8080/resttest/users/7/roles/4

On a separate note, when creating the association, it is expected to have URIs in the payload. You shouldn't need to write the whole URL in the body, this should be enough:

PUT localhost:8080/resttest/users/7/roles
Content-type: uri-list
Body: /roles/4

Hope this helps.

查看更多
登录 后发表回答