SharkAPI
SharkAPI is a library that will help you to create APIs (REST or GraphQL) faster and easier.
Introduction
I came from Ruby on Rails environment, but I also love JavaScript and NodeJs. Everyone knows that Ruby on Rails is very productive and NodeJs is very flexible. I think that is possible to merge this.
I realy like the principle "Don't repeat yourself". But there are many cases that we need to repeat a lot of data in software development.
For example, if you define data structure in ORM layer, why do you need to repeat the same fields and relationships at the controller layer?
Other example, why do you need to repeat rules of filters, sorts and paginations in every controller?
The main idea of SharkAPI is import the data structure (metadata) from ORM and generate API automatically with stantard rules.
For edge cases the SharkAPI provide hooks for customize some features. You are also free for add custom routes (for REST API) or types (for GraphQL).
Goals of SharkAPI:
- Create API without repeat data structure (metadata).
- Add standart rules about filters, sorts and paginations.
- Allow hooks for customize.
- Allow custom routes or types for edge cases.
- Standardize without losing flexibility.
Basic Concept / Architecture
SharkAPI isn't a framework. SharkAPI is a library that will integrate with others frameworks and libraries.
There are three layers in SharkAPI: Server, ORM and Core.
In Server layer you can choice between REST API or GraphQL. REST API Server have Express.js as dependency. GraphQL Server have a GraphQL.js as dependency.
In ORM layer, at moment SharkAPI support only Sequelize.js, but there are a plans for support TypeORM and Mongoose. This layer is responsable for read metadata (structure) and run queries.
Core is a layer that have a server and many entities of ORM. When server need to know some metadata, core layer will intercept this communication for get the choose ORM.
Dependencies and versions
tool | version |
---|---|
Node.js | >= v12 |
sequelize | >= v6 |
express | >= v4 |
body-parser | >= v1 |
graphql | >= v15 |
graphql-iso-date | >= v3 |
Usage: REST API with Sequelize
Instalation:
npm install sharkapi --save npm install express --savenpm install body-parser --savenpm install sequelize --savenpm install sqlite3 --save
Example:
let express = ;let bodyParser = ;let Sequelize DataTypes = ; let SharkAPI ServerRestAPI SequelizeEntity = ; let expressApp;let sequelize; async { await ; ; ;}; { sequelize = dialect: 'sqlite' storage: 'database.sqlite' ; await sequelize; let City = sequelize; let Person = sequelize; let Car = sequelize; Person; City; Car; Person; City; Person; Car;} { expressApp = ; expressApp; let port = processargv2 || 3000; expressApp;} { let sharkAPI = ; let server = sharkAPI express: expressApp ; sharkAPI sequelizemodelsCity; sharkAPI sequelizemodelsPerson; sharkAPI sequelizemodelsCar; server;}
The above example, will generate the following endpoints:
- City entity
GET /cities
GET /cities/:id
POST /cities
PATCH /cities/:id
PUT /cities/:id
DELETE /cities/:id
- Person entity
GET /people
GET /people/:id
POST /people
PATCH /people/:id
PUT /people/:id
DELETE /people/:id
- Car entity
GET /cars
GET /cars/:id
POST /cars
PATCH /cars/:id
PUT /cars/:id
DELETE /cars/:id
Examples for parameters:
GET /cities?sort=name # Sort ascending by name GET /cities?filter[name]=london # Filter by name GET /cities?include=people # Relationship with People GET /cities?include=people.cars # Relationship with Cars through People (with DOT) GET /people?sort=-name # Sort descending by name GET /people?include=cars,city # Relationship with Cars and City (with COMMA)
Usage: GraphQL with Sequelize
Instalation:
npm install sharkapi --save npm install express --savenpm install body-parser --savenpm install sequelize --savenpm install sqlite3 --save npm install express-graphql --savenpm install graphql --savenpm install graphql-iso-date --save
Example:
let express = ;let bodyParser = ;let graphqlHTTP = ;let graphql = ;let graphqlIsoDate = ;let Sequelize DataTypes Op = ; let SharkAPI ServerGraphQL SequelizeEntity = ; let expressApp;let sequelize; async { await ; ; ;}; { sequelize = dialect: 'sqlite' storage: 'database.sqlite' ; await sequelize; let City = sequelize; let Person = sequelize; let Car = sequelize; Person; City; Car; Person; City; Person; Car;} { expressApp = ; expressApp; let port = processargv2 || 3000; expressApp;} { let sharkAPI = ; let server = sharkAPI graphql graphqlIsoDate ; sharkAPI sequelizemodelsCity; sharkAPI sequelizemodelsPerson; sharkAPI sequelizemodelsCar; let schema = server; expressApp;}
The above example, will generate the following types:
# Queries Cities: CityConnectionCity: City People: PersonConnectionPerson: Person Cars: CarConnectionCar: Car # Mutations createCity: CityupdateCity: CitydeleteCity: City createPerson: PersonupdatePerson: PersondeletePerson: Person createCar: CarupdateCar: CardeleteCar: Car
Hooks
Hooks are functions that you pass to SharkAPI that will intercept some behavior. For example, if you need to create some custom filter you must to create a hook.
For default, SharkAPI only generate filter with equal
operator, but you can create a hook to use a filter with like
operator.
sharkAPI Person hooks: trigger: 'filter' match: 'name_like' { contextwherename = Oplike: `%%` ; } ;
Property trigger
is type of hook and can have the following values:
- index-before
- index-after
- show-before
- show-after
- create-before
- create-after
- update-before
- update-after
- delete-before
- delete-after
- filter
- relationship
- sort
- page
Property match
can be a string
or regex
. If you have match: /./
in the previous example will intercept all filters.
Argument context
is query object, in this case sequelize obeject. You can change this object as you wish.
Argument name
have the content that was match with match
property.
Argument value
have the content passed as value.
Here are others examples:
sharkAPI Person hooks: trigger: 'sort' match: 'city_name' { contextinclude; contextorder; } trigger: 'relationship' match: 'cars' { contextinclude; } ;
Demo App
Click here to see source of demo app
TO-DO List
- Refactor some parts for reduce coupling to become unit tests more readable
- Support TypeOrm
- Support Mongoose
- Support Firebase