CRUD REST API design part 1: simple things

I will try to accumulate all my knowledge / experience about CRUD REST, will teach how to MAKE your API understandable and self-explainatory.

If you dont like reading just ENJOY THE PICTURES 🙂

Lets talk today about simple things

easy right? now to GET event 99% of people would do this…

GET /event/{id}
{
 "id": 1,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "HACKATHON",
 "headline": "Alexey's lonely hackathon",
 "text": "Please someone come :("
}

this is OBVIOUS, and it’s cool because everybody will think this way – no need to explain what this api do.

Now if you call /event without id what you will get?

GET /event
[
 {
 "id": 1,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "HACKATHON",
 "headline": "Alexey's lonely hackathon",
 "text": "Please someone come :("
 },
 {
 "id": 2,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "SPORT",
 },
 {
 "id": 3,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "COFFEE_BREAK",
 "headline": "Sunshine coffee",
 "text": "Arabica + Robusta strong"
 }
]

if you didnt specify the {id} this means id doesnt matter; this means you get a list of events (I think at least 50% would mean that)

Lets try POSTing new event

POST /event
{
 "type": "HACKATHON",
 "headline": "Elon Musk's hackathon",
 "text": "It's gonna be on Mars"
}
4
{
 "id": 4,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "HACKATHON",
 "headline": "Elon Musk's hackathon",
 "text": "It's gonna be on Mars"
}

we definitely need to send some data in this one, so how our request would look like? the most OBVIOUS body I can think of – same response that we got from GET /event/{id}; so we’re using the same event json we got from server to actually create new one EXCEPT that there is no id in request (because event is new)

Also think of what we gonna get in response. Because you actually want to keep track of what you just created you need to return id of the created event. Or in some cases creation may affect initial request state – add some DEFAULT fields for example – so consider response_v2 example as an alternative (I think it’s better because it kindly added "date" for us).

Updating event PUT request looks like guess what? Of course the same as POST request

POST /event
{
 "id": 4,
 "text": "Actually lets do it on the Moon"
}
{
 "id": 4,
 "date": "2018-03-30T23:28:26.578Z",
 "type": "HACKATHON",
 "headline": "Elon Musk's hackathon",
 "text": "Actually lets do it on the Moon"
}

But there are some catches, lets consider the following situations

  1. Probably our update affected other field like lastUpdateDate for example
    {
     "id": 4,
     "text": "Actually lets do it on the Moon"
    }
    {
     "id": 4,
     "date": "2018-03-30T23:28:26.578Z",
     "lastUpdateDate": "2018-03-30T23:28:26.578Z",
     "type": "HACKATHON",
     "headline": "Elon Musk's hackathon",
     "text": "Actually lets do it on the Moon"
    }

    to return an updated STATE of entire object is a good idea – better than just returning “OK” or “Done” or “id” as in POST example

  2. What if there is a validation error? I would like to see smth like this
    {
     "id": 4,
     "text": "Actually lets do it on the Moon"
    }
    {
     "errorCode": 2,
     "errorMsg": "Sorry, nobody can mess with Elon Musk's events"
    }

    First – you can make entirely different response structure if you’re using different HTTP response status – 400 Bad Request in this case suits very well for validation errors

    As an alternative you can make the following base model for all your entities


    in this case you’re always returning 200 but it contains information about “how the request actually went”

    {
     "id": 4,
     "text": "Actually lets do it on the Moon"
    }
    {
      "result": {
        "successful": false,
        "errorCode": 2,
        "errorMsg": "Sorry, nobody can mess with Elon Musk's events"
      }
    }
    {
      "result": {
        "successful": true
      },
      "data": {
        "id": 4,
        "date": "2018-03-30T23:28:26.578Z",
        "lastUpdateDate": "2018-03-30T23:28:26.578Z",
        "type": "HACKATHON",
        "headline": "Elon Musk's hackathon",
        "text": "Actually lets do it on the Moon"
      }
    }

    i cannot say which approach is good or bad – you need to decide it yourself

How about deleting events? Seems easy

DELETE /event/{id}
4
(nothing just status 200)
{
  "result": {
    "successful": true
  }
}

Response may be different: id of deleted element, 200 status / 400 status with error, or Response with result successful true / false

Summary

Today I told you about basic CRUD operations you can have with your entities, they are easy though as you may see, there are some options to choose:

  • GET /event/{id}
    • request: no
    • response: event with id={id}
  • GET /event
    • request: no
    • response: whole events list
  • POST /event
    • request: event json (same as in GET but without id)
    • response: just an id / updated event json / validation error (400) or complex Response with Result and data
  • PUT /event
    • request: event json (may be partial)
    • response: updated event json / validation error (400) or complex Response with Result and data
  • DELETE /event/{id}
    • request: no
    • response: id of deleted event / status 200 / result object

PART 2 IS COMING SOON

Leave a Reply

Your email address will not be published.