0

Let's say I have two objects: Student and Homework. Homework has Student as fk:

CREATE TABLE student (
    id serial PRIMARY KEY,
    name varchar(100)
)

CREATE TABLE homework (
    id serial PRIMARY KEY,
    topic varchar(255),
    student_id int REFERENCES student(id)
)

Is there any convention for what is the right way to structure the API endpoints for CRUD?
If I want to create a new homework for a student, I could send a json body with student id

{
    "student_id": 1,
    "topic": "topic
}

to POST https://website.com/api/v1/homework.

Or I could send

{
    "topic": "topic
}

to POST https://website.com/api/v1/students/{student_id}/homework and take student id from URL.

In second case I would be sending a POST request with incomplete fields and in first case I would have one extra endpoint (since I would need /students/{id}/homework anyway to fetch particular student's homework.)

1
  • 1
    I write client code for an API that uses the second approach. Commented Feb 14, 2022 at 10:43

1 Answer 1

3
+50

You have two entities Student and Homework. A Homework entity belongs to Student.

So the more semantically correct approach would be:

  • Create Homework Endpoint:

    POST https://website.com/api/v1/students/{student_id}/homeworks
    
  • Delete Homework EndPoint:

    DELETE https://website.com/api/v1/homeworks/{homework_id}
    

There are no agreed rules but this is generally a widely followed pattern:

If A owns B, and you want to create a new B entity, your path will be like /A/{A_Id}/B.

  • Boilerplate Request:

    POST /ParentEntity/ParentId/ChildEntity
    

Now B was created and you have an id associated with it, so you can directly alter B (say for any mutation operation, POST, DELETE, PUT, PATCH).

DELETE /B/{id}

PUT /B{id}

OR

POST /B/{id}/delete

POST /B/{id}/update

(this one is followed in StackOverflow Docs, where your request intention/action is defined in URL suffix instead of being defined by your HTTP method)


Why do we do directly alter B? Why not do something like:

DELETE /A/{Aid}/B/{Bid}

Because /A/{Aid} would be redundant information. Since it is guaranteed that {Bid} would always be unique even though multiple B entities can belong to a single A entity.


Additional References:

You can see the API pattern Stackoverflow has used for their APIs here for any future reference. https://api.stackexchange.com/docs?tab=category#docs

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

4 Comments

Adding /delete to your URI for a DELETE request is definitely not a widely accepted pattern.
@Evert yep overlooked that. I initially had POST for both delete and update. Fixed. Thanks.
Thank you for detailed answer, what's the point for using POST .../homework/add instead of just POST .../homework?
It should have been homeworks instead of homework. My bad. In that case, you will have {parent}/{parentId}/homeworks/add and {parent}/{parentId}/homeworks. When you use POST for everything, your endpoint suffix tells you the intention in a sense, and if you are doing that then {parent}/{parentId}/homeworks would be a GET request that returns a JSON of homeworks on that parentId.

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.