1.0.0 • Published 4 years ago

achilles v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

achilles NPM Module NPM Downlaods Travis CI Code Climate

A lightweight Model-View-Controller (MVC) library for building beautiful database-backed APIs. Good web applications are built on good APIs, but that doesn't mean hours should be wasted away while a web application that binds a REST API to the database and covers validation, authentication and pagination is crafted. Achilles crafts an API from the database schema:

var achilles = require("achilles");
var mongodb = require("achilles-mongodb");
var db = new mongodb.Connection("mongodb://127.0.0.1:27017/test");

var Book = achilles.Object.extend({
    title:String,
    author:String,
    rating:Number,
    datePublished:Date,
    readership:[String]
});

db.register(Book, "books");

var BookService = new achilles.Service(Book); // Instance of express.Router
BookService.listen(8080);

Thus you have a fully functioning REST API:

OPTIONS  /
HEAD     /
GET      /
POST     /
HEAD     /:id
GET      /:id
PUT      /:id
DELETE   /:id

Installation

npm install achilles --save

Express

achilles.Service is secretly just an instance of an express.Router, so to use it in any Express application:

app.use("/api", new achilles.Service(model));

Comprehensive Overview

Whether the web apps or native apps are the future, there is something they both rely on. They rely on an API to communicate with the server. A JSON HTTP REST API to be precise. JSON is the format in which objects are encoded. HTTP is the protocol by which messages are sent. REST is the schema endpoints. Achilles was built because doing all of this was difficult, time-consuming and tedious. What made it worse was performing validation, authentication and pagination. Validation is making sure the data is in the correct format. Authentication is making sure that the user is only allowed to perform the actions he/she has been permitted to do. Pagination is giving the client only the items requested, so page-based interfaces can be created. The idea was simple why not create something that would take in a database schema and create an API around that, that will handle all of those things, so you can spend most of your time working on building the client-side web/native application.

It's all possible by introducing a strong-typed Object-Oriented Programming system, like in Java or C++. By default JavaScript is weak-typed, so variables can be of any data type, but it is no use assigning a string to an age property! Achilles sorts all of that out.

Here's the cool thing though: Achilles also works on client-side JavaScript. What does that mean? Well if you're making a web app server-side classes, client-side. Also on the client-side data is cached (in LocalStorage/IndexedDB/WebSQL) so it doesn't have to be constantly reloaded.

Objects

Objects, whose foundation is achilles.Object, are based on Mongoose schemata. To create your own class, subclass achilles.Object, by usomg the .extend() static method. When you subclass an object all properties, methods and static methods are inherited unless overriden. The .extend() method takes an object that map property names to classes. To describe an array of a class, put the class in square brackets:

var Person = achilles.Object.extend({
    name: String,
    age:Number,
    children: [People]
});

var Zed = new Person({
    name: "Zed"
});

Methods

Methods are added like normal using prototype and static methods are assigned directly onto the constructor:

Person.prototype.howManyChildren = function() {
    return this.children.length;
}

Person.createLucy = function() {
    return new Person({
        name:"Lucy"
    });
}

Constructors

achilles.Object has an un-overidable default constructor, that takes in an object containing all the default properties of an object. However if a method initialise exists, that constructor will call that method to initialise the object.

Events

achilles.Object extends events.EventEmitter, therefore you can listen for change events and for events to a specific key, by change:key:

var person = new Person({
  name:"Chloe"
});

person.on("change", function(key) {
  console.log("The property " + key + " was changed");
});

person.age = 5;
// "The property age was changed"

person.on("change:name", function() {
  console.log("Name change!!!");
});

person.name = "Rachel";
// "The property name was changed"
// "Name change!!!"

Models

To instantiate a connection to a data source you must use the appropriate adapter to that data source. For example, if you are trying to connect to a REST API, especially if it is created by achilles.Service, you can use achilles.Connection. This is most probably for client-side use. For server-side use there is a MongoDB adapter. To add methods and static methods such as get, save and del, you must register your class with the database, e.g.:

var db = new achilles.Connection("/api");
db.register(Person, "people");

db.register(model, descriptor) takes two arguments. The first one is the model, and the second is a description (conventionally a pluralised form of the class name), which is used in some adapters, such as the MongoDB, to specify the sub-database/collection where the documents/records of the specific class are stored, but always in the permissions system, which is covered later and ensures users can only perform operations, to which they have been given permission to complete.

Querying the database

To query the database use the get(options, cb) static method, where cb if a function of the signature (err, docs). By default docs is an array of all docs. To limit how many docs are sent specify a limit and a skip in options.

Person.get({limit: 10, skip: 10}, function(err, docs) {
  if(err) {
    console.log("There was an error: " + err);
  } else {
    console.log(docs); // Docs will contain records 11-20 (10 in total)
  }
});
The id property

To ensure consistency, the id property is always used and always returns a String representation of the id used in the database, regardless of how it is stored in the database.

Get by id

To get a model by id use the getById(id, cb) static method, where cb is a function of the signature (err, doc).

Person.getById("13532FSDFDS", function(err, doc) {
  if(err) {
    console.log"There was an error: " + err);
  } else {
    console.log(doc.id); // "13532FSDFDS"
    console.log(doc.name);
  }
});
Delete by id

To delete a model by id use the getById(id, cb) static method, where cb is a function of the signature (err).

Person.delById("13532FSDFDS", function(err) {
  if(err) {
    console.log("There was an error: " + err);
  } else {
    console.log("Document was successfully deleted");
  }
});
Saving a model

To save a model use the save(cb) instance method, where cb is a function of the signature (err, doc).

Deleting a model

To delete a model use the del(cb) instance method, where cb is the function of the signature (err).

Services

achilles.Service(model) takes in one argument, that is the model of which to create an API. The API has several endpoints. All endpoints use JSON as the format.

OPTIONS /, OPTIONS /:id

Returns all the possible methods at that endpoint in the Allow header.

HEAD /, HEAD /:id

Equivalent to a GET request but only returns HTTP headers, not the body. Useful in getting the Content-Length of something for example.

GET /

Returns all the items in the database, that match the criteria in the where parameter. If there isn't one, then it will return all the documents. E.g.:

/?where={age:{$lt:4}}

The where parameter uses the MongoDB API syntax.

Pagination

To request a certain number of items, use the HTTP Range header:

Range: items=0-9

GET /:id

Returns a given record in the database, by its id.

POST /

Creates a new record in the database. It accepts a JSON body for the contents. Performs validation.

PUT /:id

Update a record in the database, by its id. It will completely overwrite the existing contents with the JSON body. Performs validation. Idempotent.

PATCH /:id

Updates a record in the database, by its id. It accepts a JSON PATCH body containing only the changes. It does not completely overwrite the existing contents, but only applies the updates. Performs validation.

DELETE /:id

Delete a record in the database, by its id. Idempotent.

1.0.0

4 years ago

1.0.0-alpha.0

4 years ago

0.23.75

4 years ago

0.23.74

4 years ago

0.23.73

4 years ago

0.23.72

4 years ago

0.23.71

4 years ago

0.23.70

4 years ago

0.23.69

4 years ago

0.23.68

4 years ago

0.23.67

4 years ago

0.23.66

4 years ago

0.23.65

4 years ago

0.23.64

4 years ago

0.23.63

4 years ago

0.23.62

4 years ago

0.23.61

4 years ago

0.23.60

4 years ago

0.23.59

4 years ago

0.23.58

4 years ago

0.23.57

4 years ago

0.23.56

4 years ago

0.23.55

4 years ago

0.23.54

4 years ago

0.23.53

4 years ago

0.23.52

4 years ago

0.23.51

4 years ago

0.23.50

4 years ago

0.23.49

4 years ago

0.23.48

4 years ago

0.23.47

4 years ago

0.23.46

4 years ago

0.23.45

4 years ago

0.23.44

4 years ago

0.23.43

4 years ago

0.23.42

4 years ago

0.23.41

4 years ago

0.23.40

4 years ago

0.23.39

4 years ago

0.23.38

4 years ago

0.23.37

4 years ago

0.23.36

4 years ago

0.23.35

4 years ago

0.23.34

4 years ago

0.23.33

4 years ago

0.23.32

4 years ago

0.23.31

4 years ago

0.23.30

4 years ago

0.23.29

4 years ago

0.23.18

4 years ago

0.23.17

4 years ago

0.23.16

4 years ago

0.23.15

4 years ago

0.23.14

4 years ago

0.23.13

4 years ago

0.23.12

4 years ago

0.23.9

4 years ago

0.23.5

4 years ago

0.23.4

4 years ago

0.23.3

4 years ago

0.23.1

4 years ago

0.23.0

4 years ago

0.22.6

4 years ago

0.22.5

4 years ago

0.22.4

4 years ago

0.22.3

4 years ago

0.22.2

4 years ago

0.22.1

4 years ago

0.21.1

4 years ago

0.21.0

4 years ago

0.20.0

4 years ago

0.19.1

4 years ago

0.19.0

4 years ago

0.18.8

4 years ago

0.18.7

4 years ago

0.18.6

4 years ago

0.18.5

4 years ago

0.18.4

4 years ago

0.18.2

4 years ago

0.17.1

4 years ago

0.17.0

4 years ago

0.16.6

4 years ago

0.16.5

4 years ago

0.16.4

4 years ago

0.16.3

4 years ago

0.16.2

4 years ago

0.16.1

4 years ago

0.16.0

4 years ago

0.15.16

4 years ago

0.15.15

4 years ago

0.15.14

4 years ago

0.15.13

4 years ago

0.15.12

4 years ago

0.15.11

4 years ago

0.15.10

4 years ago

0.15.9

4 years ago

0.15.8

4 years ago

0.15.7

4 years ago

0.15.6

4 years ago

0.15.5

4 years ago

0.15.4

4 years ago

0.15.3

4 years ago

0.15.2

4 years ago

0.15.1

4 years ago

0.15.0

4 years ago

0.14.4

4 years ago

0.14.3

4 years ago

0.14.2

4 years ago

0.14.1

4 years ago

0.14.0

4 years ago

0.12.0

4 years ago

0.11.3

4 years ago

0.11.2

4 years ago

0.11.1

4 years ago

0.11.0

4 years ago

0.10.4

4 years ago

0.10.3

4 years ago

0.10.2

4 years ago

0.10.1

4 years ago

0.10.0

4 years ago

0.9.0

4 years ago

0.8.3

4 years ago

0.8.0

4 years ago

0.7.7

4 years ago

0.7.6

4 years ago

0.7.5

4 years ago

0.7.4

4 years ago

0.7.3

4 years ago

0.7.2

4 years ago

0.7.1

4 years ago

0.7.0

4 years ago

0.6.0

4 years ago

0.5.16

4 years ago

0.5.15

4 years ago

0.5.14

4 years ago

0.5.13

4 years ago

0.5.11

4 years ago

0.5.10

4 years ago

0.5.5

4 years ago

0.5.4

4 years ago

0.5.3

4 years ago

0.5.2

4 years ago

0.5.1

4 years ago

0.5.0

4 years ago

0.3.5

4 years ago

0.3.4

4 years ago

0.3.2

4 years ago

0.3.0

4 years ago

0.1.18

4 years ago

0.1.17

4 years ago

0.1.16

4 years ago

0.1.14

4 years ago

0.1.13

4 years ago

0.1.12

4 years ago

0.1.11

4 years ago

0.1.10

4 years ago

0.1.9

4 years ago

0.1.8

4 years ago

0.1.7

4 years ago

0.1.5

4 years ago

0.1.4

4 years ago

0.1.3

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago

0.0.2

4 years ago

0.0.1

4 years ago

0.0.0

4 years ago