Create a simple Api
var tastypie = require('tastypie')
var Api = tastypie.Api
var hapi = require('hapi')
var server = new hapi.server
var v1 = new Api('api/v1' )
var Resource = tastypie.Resource.extend({
fields:{
lastName:{ type:'char', attribute:'name.first' },
fisrtName:{type:'char', attribute: 'name.last'}
}
})
v1.use('test', new Resource() );
server.connection({port:2000})
server.register( v1, function( ){
server.start(function(){
console.log('server listening localhost:2000')
});
})
Get Data
// GET /api/v1/test
{
"meta":{
"count":1,
"limit":25,
"next":null,
"previous":null
},
"data":[{
firstName:"Bill",
lastName:"Bucks",
uri:"/api/v1/test/1"
}]
}
Auto Schema
// GET /api/v1/test/schema
{
"fields": {
"firstName": {
"blank": false,
"default": null,
"help_text": "Forces values to string values by calling toString",
"nullable": false,
"readonly": false,
"type": "string",
"unique": false
},
"lastName": {
"blank": false,
"default": null,
"help_text": "Forces values to string values by calling toString",
"nullable": false,
"readonly": false,
"type": "string",
"unique": false
},
"uri": {
"blank": false,
"default": null,
"help_text": "Forces values to string values by calling toString",
"nullable": false,
"readonly": false,
"type": "string",
"unique": false
}
},
"filtering": {},
"format": "application/json",
"limit": 0,
"methodsAllowed": [
"get",
"put",
"post",
"delete",
"patch",
"head",
"options"
]
}
Built-in Fields
field ( ApiField ) - Generic noop field
object ( ObjectField ) - Generic no-op field
char ( character / CharField ) - Converts values to strings
array ( ArrayField ) Converts comma sparated strings into arrays
int ( int / IntegerField ) converts numeric values into integers using parseInt
float ( FloatField ) Converts values to floating point number using parseFloat
bool ( BooleanField ) Forces values to booleans
datetime ( DateTimeField ) Attempts to convert date time strings into date objects
file ( FileField ) A field that pipes a stream to a configured location, and store a path
filepath ( FilePathField ) A field that handles file locations rather than dealing with streams or binary data
This allows for full HTTP support and basic CRUD operations on a single enpoint - api/v1/test
curl -XPOST -H "Content-Type: applciation/json" -d '{"test":"fake"}' http://localhost:3000/api/v1/test
curl -XPUT -H "Content-Type: applciation/json" -d '{"test":"real"}' http://localhost:3000/api/v1/test
curl -XDELETE http://localhost:3000/api/v1/test/fake
HTTP Verbs
This is how tastypie handles the base HTTP Methods
GET returns a list of resource instance or a specific resource instance
DELETE removes a specific resource instance
PUT REPLACES a resource instance. This is not a partial update. Any optional fields not define we be set to undefined
PATCH a PARTIAL update to a specific resource instance.
OPTIONS, HEAD, TRACE, and CONNECT are left to implementation on a per resource bases
Serialization
The base serializer can deal with xml
, json
and jsonp
out of the box. Serialization method is determined by the Accept
header or a format
query string param
curl -H "Accept: text/xml" http://localhost:3000/api/v1/test
curl http://localhost:3000/api/v1/test?format=xml
NOTE:* hapi captures application/foo so for custom serialization, we must use text/foo
Example FS resourse
Of course, Tastypie is not tied to Mongo or mongose, you can use the default resource type to create to put a Rest API around anything. The mongo resource just does a lot of the set up for you.
Here is a resource that will asyncronously read a JSON file from disk are respond to GET requests. Supports XML, JSON, paging and dummy cache out of the box.
var hapi = require('hapi');
var fs = require('fs')
var path = require('path')
var Resource = require('tastypie/lib/resource')
var Api = require('tastypie/lib/api')
var fields = require("tastypie/lib/fields")
var Class = require('tastypie/lib/class')
var Options = require('tastypie/lib/class/options')
var Serializer = require('tastypie/lib/serializer')
var debug = require('debug')('tastypie:example')
var app;
// make a simple object template to be populated
// This could be a Model class just as easily
function Schema(){
this.name = {
first: undefined, last: undefined
}
this.age = undefined;
this.guid = undefined;
this.range = []
this.eyeColor = undefined;
};
var Base = Class({
inherits:Resource
,options:{
template: Schema // Set the schema as the Object template
}
,fields:{
// remap _id to id
id : { type:'ApiField', attribute:'_id' }
, age : { type:'IntegerField' }
// can also be a field instance
, eyeColor : new fields.CharField({'null':true})
, range : { type:'ArrayField', 'null': true }
, fullname : { type:"CharField", 'null':true }
// remap the uid property to uuid.
, uuid : { type:'CharField', attribute:'guid'}
, name : { type:'ApiField'}
}
, constructor: function( meta ){
this.parent('constructor', meta )
}
// internal lower level method responsible for getting the raw data
, get_objects: function(bundle, callback){
fs.readFile( path.join(__dirname, 'example','data.json') , callback)
}
// internal low level method reponsible for dealing with a POST request
, create_object: function create_object( bundle, opt, callback ){
bundle = this.full_hydrate( bundle )
// this.save( bundle, callback )
callback && callback(null, bundle )
}
// per field dehydration method - generates a full name field from name.first & name.last
, dehydrate_fullname:function( obj, bundle ){
return obj.name.first + " " + obj.name.last
}
// top level method for custom GET /upload
, get_upload: function( bundle ){
this.respond({data:{key:'value'}})
}
// method that retreives an individual object by id.
// becuase it's in a flat file, read it, filter and return first object
,get_object: function(bundle, callback){
this._get_list(bundle,function(e, objects){
var obj = JSON.parse( objects ).filter(function( obj ){
return obj._id = bundle.req.params.id
})[0]
callback( null, obj )
})
}
// Proxy method for delegeting HTTP methods to approriate resource method
, dispatch_upload: function(req, reply ){
// Do additional magic here.
return this.dispatch('upload', this.bundle( req, reply ) )
}
// adds a custom route for upload in addition to standard crud methods
, prepend_urls:function(){
return [{
route: '/api/v1/data/upload'
, handler: this.dispatch_upload.bind( this )
, name:'upload'
}]
}
});
var api = new Api('api/v1', {
serializer:new Serializer()
})
app.connection({port:process.env.PORT || 2000 });
api.user('data', new Base() );
app.register( api, function(e){
app.start(function(){
console.log('server is ready')
});
});
Now you can read data from a file with your rest API
curl http://localhost:2000/api/v1/test
curl http://localhost:2000/api/v1/test?format=xml
curl http://localhost:2000/api/v1/test/1
curl http://localhost:2000/api/v1/test/2
curl http://localhost:2000/api/v1/test/2?format=xml
Resource based REST Framework built ontop of hapi.js
- Since:
-
- 0.0.1
- Source:
Requires
- module:tastypie/lb