The repo for this project can be found here: https://github.com/irlnathan/sails-crud-api
Transcript
Howdy and welcome back to part II of our three part series. In the last episode we learned how the http request/response protocol works with routes, controllers, actions and models to deliver a restful json CRUD api. In this episode we’ll take the concepts we learned and use them to build the api from scratch. In the final episode we’ll explore how sail’s blueprints: actions and routes can be used to create that same restful json CRUD api automatically for any of your controllers and models.
Let’s review what we’re trying to accomplish.
Our api will be used to access and update information that tracks our sleep patterns including how much we sleep each night and the quality of that sleep.
So we want the api to be able to respond to requests to find, create, update or delete instances of our sleep model. We’ll create actions that corresond to the requests and then build up routes that match the appropriate http verbs and paths with the corresponding controller and action.
- So the find request will use the http verb
get
with the path/sleep/:id?
and bind to thesleep
controller andfind
action. - The create request will use the verb
post
with the path/sleep
and bind to thesleep
controller and thecreate
action. - The update request will use the verb
put
with the path/sleep/:id?
and bind to thesleep
controller and theupdate
action. - and finally, the delete request will use the verb
delete
with the path/sleep/:id?
and bind to thesleep
controller anddestroy
action.
The actions will then use the model methods to find, create, update or destroy the model as requested and use the parameters hours_slept
and sleep_quality
to pass any necessary information within the request through the action to the model. The action will then respond with the request status as well as any model instance or instances required.
So let’s get started. I’m going to bring up a terminal window and we’re going to create a new sails project called mySleep
using sails new mySleep --linker
. and I’ll change into the mySleep
folder and generate a sleep controller and model using sails generate sleep
.
So, here’s a roadmap of what we’re going to build. I’m going to start with the create action, building the action and then building the route that will bind the find request with the sleep controller and find action. I’m going to go through each action, create it, and then build the matching route that will bind our request to the controller and action. So let’s start with the create action.
I’ll open my sleep controller found in /api/controllers/SleepController.js
and create my first action called create
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
The action is straightforward, we’re going to grab the request’s parameters in the var params
and then pass params
into the create
method of our sleep
model. If there’s an error we’ll return it and if not I’ll send a 201 status code response with the newly created model instance formatted as json.
So that’s the create
action, now I need to create a route that will bind this controller and action to our request. So let’s open the routes in /config/routes.js
and I’ll add my route after the existing home route:
1 2 3 4 5 6 7 8 9 10 |
|
The route consists of the verb post
to the path /sleep
which is bound to the sleep
controller and the create
action. So let’s make sure our create action is working. I’ll go into the terminal, start sails with sails lift
. I’ll again be using the POSTMAN chrome extension to test our requests. We’ll be using the http verb POST
to the path /sleep
adding two parameters hours_slept
and sleep_quality
. When I click send, Sails returns my newly created record as json.
1 2 3 4 5 6 7 |
|
So let’s take a look at our api roadmap. We’ve built the create action as the first of the four actions of our api. Next, we’ll build the find
action and then we’ll build a route that will bind Sleep controller and find action to our request. For the action let’s go back into the SleepController.js
file and look at the find action code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
|
Let’s also take a look at the route that will bind our request to the sleep controller and find
action in /config/routes.js
:
'get /sleep/:id?': 'SleepController.find'
The route points to our find
action but look the end of the path, what’s up with :id?
, and the question mark? The question mark makes the id
parameter optional. That way we capture both the request 'get /sleep'
as well as 'get /sleep/:id'
.
The find action will be our most complex action of the four in our api. This is because we have to provide for a request finding a single instance of the model, multiple instances of the model, as well as using criteria and options to narrow and/or limit the scope of the find request.
So within our find action, we’ll attempt to assign a parameter called id
to the var id
. The next line of code looks to see if the id
is a shortcut. I’m going to skip over this part because shortcuts are part of sail’s blueprints which we’ll be discussing in the third episode.
So if the id
exists we’re going to assume that the request is looking for a particular model instance. We’ll pass the id
to the findOne
model method and if we don’t get back an instance of sleep
in the callback, we’ll return or respond with a status code of 404
— not found
. On success, we’ll return and respond with the model instance formatted as json.
Checking for multiple model instances. If no id
is provided we’ll start looking for other criteria or options that may have been passed as a parameter for finding one or more model instances. Criteria is placed in a where
clause which is just the key name for a criteria object. For example, if your want to find all model instances where sleep_quality = good, your parameters would look like this: ?where={sleep_quality: "good"}
. We’ll also check for options that further limit the result in some way. For example, let’s say we only want the first 5 model instances of our result. The parameters would look like this: ?where={sleep_quality: "good"}&limit=5
.
So if where
exists as a parameter and the value for it is a string, we’ll just parse it as json and assign it to the var where
. Even if where
doesn’t exist we’ll still look for the keys limit
, skip
, and sort
and place them within the options object. Finally, we’ll pass the options object to the Find model method and if we don’t get back an instance of sleep
in the callback, we’ll return or respond with a status code of 404
— not found
. On success, we’ll return and respond with the model instance(s) formatted as json.
So we have the find action complete, let’s make sure all of this works. I’ll head back to the terminal and restart the sails server using sails lift
and then open a browser with the POSTMAN chrome extension. I’ve added a few more instances of our sleep model. Let’s take a look by sending a get
request to the path /sleep
. After sending the request the api returned five instances of the model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Since we didn’t provide an id
or any criteria or options, the api used the find model method and returned all instances of the model formatted as json.
Next, let’s make a get
request to the path /sleep/2
. After pressing send, the api returns a single instance of the model with an id
of 2:
1 2 3 4 5 6 7 |
|
Now let’s try a request with some criteria. We’ll look for any model instances with an id
greater than 1:
1 2 3 4 |
|
After making the request, the api returns four of the five model instances with id
’s greater than 1.
Finally, I’m going to combine the criteria with some options. I’m going to make a get
request to the path /sleep
for model instances with an id
not equal to 4, limited to 3 model instances and in descending order.
1 2 3 4 |
|
After making the request, the api returns three instances of the model in descending order.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Now that we know that our find
action is battle tested, let’s go back to our api roadmap. By building the create action and route and the find action and route we’re half way through our api. Next, we’ll build the update
action and then we’ll build a route that will bind the Sleep controller and update action to our request. Let’s head back into the SleepController.js
file and look at the update action code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
The update action consists of finding the id
of the model instance to update coupled with the criteria that will be updated. If there’s no id
as a parameter we respond with a 400 status— ‘No id provided’. Next we attempt to update the model instance using the id
and criteria provided. If there’s an error we’ll return it and if not respond with the updated model instance formatted as json.
So now that we have the update action complete, we’ll bind that action to the request forming a new update route:
'put /sleep/:id?': 'SleepController.update'
The route points to our update
action and uses the same :id?
pattern that we used in the find
route.
Let’s make sure all of this works. I’ll restart the sails server using sails lift
and then open a browser with the POSTMAN chrome extension. I’m going to first make a put
request to the path:
http://localhost:1337/sleep/3?added_attrib=12
After making the request, the api returns our instance of the model that has an id of 3
with our added attrib formatted as json.
Next, I’ll make a put
request to:
1 2 3 4 |
|
…but instead of using query parameters, I’ll pass the update via the request body. After making the request, the api returns our instance of the model that has an id of 3
with our added_3 attribute formatted as json.
1 2 3 4 5 6 7 8 |
|
Now that update action and route is complete it’s time to build the last action of our api the destroy
action and then bind it to our request to form the delete
route. Let’s head back into the SleepController.js
file and look at the destroy action code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
So we’ll attempt to assign the id
param to a var called id
. If it doesn’t exist I’ll return a 400— ‘No id provided’. If an id
parameter was provided in the request, I’ll attempt to find it in the sleep
model. If the model doesn’t exist I’ll respond with a status code of 404
— not found
. If the mode instance does exist, I’ll pass the id
to the destroy method of the model returning either an error if any, or the deleted model instance formatted as json.
Next I’ll bind the destroy action with the request in its own delete
route:
'delete /sleep/:id?': 'SleepController.destroy'
Let’s check it out by restarting the sails server using sails lift
. Once again within the POSTMAN chrome extension I’ll make a delete request to the path:
destroy
http://localhost:1337/sleep/5
After sending the request the api responds with the model instance it just deleted formatted as json.
Congratulations, you’ve built a restful json CRUD api. Any client-side device that supports http requests can now hit our api’s endpoints and request and submit information about our sleep model.
In the next and final episode of this series I’ll show you how sail’s blueprints: actions and routes can be used to create this same restful json CRUD api we just created, automatically for any of your controllers and models.
Okay that was a lengthy one, As always, thanks for watching and if you get a chance, follow me on twitter @irlnathan.