Skip to content

Instantly share code, notes, and snippets.

@rixlabs
Last active July 13, 2016 09:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rixlabs/04a0e57d7db23b0e81e36bcec5954447 to your computer and use it in GitHub Desktop.
Save rixlabs/04a0e57d7db23b0e81e36bcec5954447 to your computer and use it in GitHub Desktop.
Spring boot the rails way

Pretty simple situation.

My model is 1 Product has many Bookings

the api that I have to expose is just for bookings, the product part is just description and some price that has not to be edited.

so my desired endpoints are:

GET - List of all bookings POST - Create new booking PUT - Update existing Booking

The booking contains product reference but I don't want the endpoint to be "related" with the products so I keep the mapping like this:

@RequestMapping(value = "/bookings", method= RequestMethod.GET) public List<Booking> bookingsList(){ ...

My question is about the Create endpoint. Right now it's like this

@RequestMapping(value = "/{productId}/bookings",method= RequestMethod.POST) public String create(@PathVariable String productId,@RequestBody Booking input){ ...

As you can see I had to use a PathVariable to pass the productId

I was wondering if there is a way to keep the endpoint just /bookings and still pass the productId without create a specific "request model" just for deserialization. From my RoR experience params were generic and can contains lot's of fields not properly related to a specific model(or in this case is only the ID not the object)

@snicoll
Copy link

snicoll commented Jul 13, 2016

I am confused. If the Booking object has a productId, you could perfectly have the endpoint you want and grab that value from the RequestBody. I am sure I am missing something.

@rixlabs
Copy link
Author

rixlabs commented Jul 13, 2016

Maybe I am missing something.

if the endpoint is just /booking the client should send something like this:

{"firstName":"Poldo","lastName":"Poldoni","birthDate":"12/12/1912","product_id":"1"}

But this way I cannot reach the product_id in the request body unless I create a model like this

public class BookingRequest {

    private String firstName;

    private String lastName;

    private String birthDate;

    private Integer product_id;

    private Date date;

    private boolean paid;
...

And a mapping like this

@RequestMapping(value = "/{productId}/bookings",method= RequestMethod.POST)
    public String create(@RequestBody BookingRequest input){

Or there is another way?

@rixlabs
Copy link
Author

rixlabs commented Jul 13, 2016

Sorry I forgot a part.

the original Booking model

@Entity
@Table(name = "Booking")
public class Booking {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "birth_date")
    private String birthDate;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "product_id", referencedColumnName = "id")
    private Product product;

    private Date date;

    private boolean paid;

@snicoll
Copy link

snicoll commented Jul 13, 2016

product_id doesn't match anything in your Booking object. I wouldn't map an entity directly in the view model as it ties your public API with your data model. So, yes for a BookingRequest of some kind that match your public (json) API.

There might be a way to map product_id to your product#id method, but:

a) I am guessing you don't have any setter for that field since it's something that's not supposed to change
b) you expect a full Product instance to be available when you do booking.getRequest(). It won't be and I think that's something you shouldn't have to remember.

The separate entity may looks like boilerplate at first but it's a critical aspect if you want to build a stable API for your endpoint.

@rixlabs
Copy link
Author

rixlabs commented Jul 13, 2016

a) yes is tipically autogenerated and not supposed to change.

b) yes from outside the json api I need a full Product.

So ok is not that EVIL to have a "pseudo" model for the apis.

Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment