1

I have an object Order which contains another object Person among other properties.

I'm wondering what is the best solution to create an order through a post request.


The first approach in my mind is something like this:

@PostMapping("orders/create")
public void createOrder(@RequestBody Order order) {
    orderRepository.save(order);
}

but what I don't like about this solution is that the client has to send a json string with all the information about the order and the person at the same time, like this:

{
    "date": 2023-01-01,
    "price": 10,
    "person": {
        "id": 1,
        "name": "Foo",
        ...
    }
}

How can I also make sure that the person passed in the request is actually a person that exists in my database?


The second approach that I can think of is like this:

@PostMapping("orders/create/{personId}")
public void createOrder(@PathVariable Long personId, @RequestBody Order order) {
    Person person = personRepository.findById(personId).orElseThrow();
    order.setPerson(person);
    orderRepository.save(order);
}

but this solution would require a post request like localhost:8080/orders/1 where 1 is the id of the person, which is horrible because it's too confusing.

I can't get my head around this, any insights are highly appreciated.

4
  • 2
    Are users of this endpoint authenticated, and that mapped to your Person entities? Commented Feb 13, 2023 at 21:27
  • 3
    Aside: it's not the best idea to include verbs in your endpoint paths (ie, "create"). Think of REST URLs as resources, with the HTTP verbs representing actions. So POST is inherently (by convention) a "create" action, and a POST to the resource named "orders" represents a request to create a new resource under that one. Commented Feb 13, 2023 at 21:30
  • Ideally, you get the Person object that represents the user that is currently logged in. At least I assume that the logged in user is the one placing the order. Commented Feb 13, 2023 at 21:32
  • There's no authentication involved here, it's a simple project and I didn't implement it yet. @E-Riz oh ok thank you, so it makes more sense to write @PostMapping("orders") Commented Feb 13, 2023 at 21:42

1 Answer 1

2

You're right, it doesn't make sense to send the personId to the order API. Since you're passing the personId in the RequestBody, just drop the PathVariable and use what's in the order.

@PostMapping("orders/create")
public void createOrder(@RequestBody Order order) {
   Person person = personRepository.findById(order.getPerson().getId()).orElseThrow();
   order.setPerson(person);
   orderRepository.save(order);
}

Or, as the comment by E-Riz is eluding to, if the Person is the authenticated user, get them out of the SecurityContext and look them up by their username. Then there would be no need to send the Person in the Order.

Sign up to request clarification or add additional context in comments.

2 Comments

I recommend putting this "assembly" logic in a service layer. It's usually best to keep the API layer as thin as possible; in particular, not referencing data-access layer (repositories) directly.
Please see the comment by @E-Riz; this is an important point. All three lines in this method should be pushed down into a service that takes the Order and returns the persisted order. To take this one step further, you should probably receive a DTO instead of the Entity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.