-
Notifications
You must be signed in to change notification settings - Fork 5
Getting Started
Catnap is a simple way to create and manage Resources for your REST API. But before we dive in and look at the code, let's talk a little about what a resource is.
According to the W3C,
A network data object or service that can be identified by a URI. Resources may be available in multiple representations (e.g. multiple languages, data formats, size, resolutions) or vary in other ways. This term was taken verbatim from Hypertext Transfer Protocol -- HTTP/1.1
Roy Fielding, in his dissertation about REST described a resource as:
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.
So in other words, a resource is some service that lives at a URI and that has one or more representations. In order to interact with a resource, we need to use an HTTP request method, you know, GET, POST, PUT, PATCH and DELETE. These methods have a lot of semantics baked in! For example, when we GET /users/123, we are asking for the representation of the user whose id is '123'. This HTTP transaction (request-response) is called an action.
Okay, so let's step back here. A Resource is something that:
- Is identified by a URI
- Defines actions
- Has one or more representations
This is exactly what a Resource in catnap is. Let's see how to build an API with that!
For our example, we are going to build an API that manages Users. To do that, we will have two resources:
- /users
- /users/{id}
Here is the formal description of that API using api-blueprint: Simple API
For our example, we'll use Express. Note that catnap isn't tied to Express, but it requires Express-like Routers (they need to respond to HTTP verbs.)
var express = require('express'),
app = express();
var server = app.listen(3000, function() {
console.log('Listening on port %d', server.address().port);
});
This should get us started. The above was taken directly from Express' doc.
In order to manage users, we'll need to store them somehow. This could be done in different ways, but in order to keep it simple, we'll simply use an array, like so:
var users = [{
id: '1',
name: 'foo',
email: '[email protected]',
salt: 'abc'
}, {
id: '2',
name: 'bar',
email: '[email protected]',
salt: 'def'
}];
users.findById = function (id) {
for (var i = 0; i < users.length; ++i) {
if (users[i].id === id) return users[i];
}
};
Perfect! Now we are ready to roll. Let's start with the User resource.
To create a resource, you need to call makeResource
, passing it a name and a path. The path is relative to the router.
var makeResource = require('catnap').makeResource;
var userResource = makeResource('user', '/users/:userId');
Great! Now that we have a user resource, we can define its representations. We will add two:
- The default one will return the user without its salt
- The partial one will only return the user's id and name
userResource
.representation(function(user) {
// Let's filter out the salt here.
return {
id: user.id,
name: user.name,
email: user.email,
_links: {
self: {
href: this.path.replace(':userId', user.id)
}
}
};
})
.representation('partial', function(user) {
return {
id: user.id,
name: user.name,
_links: {
self: {
href: this.path.replace(':userId', user.id)
}
}
};
})
When called with only a function, representation
will register the given representation as the "default" one. We then called representation
with 'partial' as the first parameter. This registers the following representation as 'partial'. You could use any name here.
Next, lets define the GET action.
userResource
.get(function(req, res) {
var user = users.findById(req.params.userId);
if (!user) {
return res.send(400);
}
return res.send(200, userResource(user));
})
Resources have get
, post,
put,
patchand
delete` methods. They all take connect middlewares, so it's not limited to one.
To use this Resource with our application, we need to attach it to the router:
userResource
.attachTo(app);
Et voilà. We can now move on the the Users Resource.
So you know the beat now. We first make a resource using makeResource
. Then we define its representations and actions.
var usersResource = makeResource('users', '/users')
.representation(function (users) {
return {
count: users.length,
_embedded: {
users: users.map(function (user) {
return userResource(user, 'partial');
})
}
};
})
.get(function (req, res) {
res.send(200, usersResource(users));
})
.post(function (req, res, next) {
var newUser = req.body;
console.log(newUser);
users.push(newUser);
res.send(201, userResource(newUser));
})
.attachTo(app);
Take a look at the representation
. We are using the 'partial' representation of the User Resource there. Neat, right?
And that's all it takes to implement Simple API. If you want to get the full code, you can grab it there: Get teh codz.
This is really all there is to know about catnap. As you saw, it's simple and doesn't get in your way. Have fun crafting your APIs!