The fastest way to build JSON APIs in Koa.js
Apicco is a dynamic Koa router middleware that maps folder & file structure to JSON HTTP endpoints.
app/
├── api/
│ ├── movies/
│ | ├── create.js POST /api/movies.create
│ | ├── info.js POST /api/movies.info
│ | ├── list.js => POST /api/movies.list
│ | ├── update.js POST /api/movies.update
| | └── delete.js POST /api/movies.delete
Apicco leverages convention over configuration and enables Node developers to deliver JSON APIs rapidly.
- Folder structure to JSON HTTP endpoints mapping
- Parameter validation
- Middleware interception
- Discovery endpoint
- Request body formatting
- Minimal SDK
- Versionless clients
Apicco folder structure is very simple. The top API folder, contains one folder per resource.
app/
├── api/
│ ├── resource1/
│ | ├── action1.js
| | └── action2.js
│ ├── resource2/
│ | ├── action1.js
| | └── action2.js
Each folder contains JS action files that respond to API calls. Action files, are named after the methods (actions) that a controller object holds in MVC pattern.
Apicco does not support nested resources. All resources should be located under a common parent folder. That way, your API endpoints will be kept short and simple.
Apicco mounts each action file to a /{prefix}/{resource}.{action}
POST route. All the parameters are passed to the HTTP request body. For example:
POST /api/v1/movies/create
{
"title": "Foo movie",
"description": "This is a Foo movie",
"year": 2018
}
Parameter validation is handled with Joi.
If the validation fails, an HTTP 400 response will be returned to the client, along with a short human-readable error message explaining why the request was rejected.
Apicco exposes a discovery endpoint that contains a JSON representation of all the API resources and action files and is used by SDKs (clients) upon initialization.
The discover GET endpoint is mounted at /{prefix}/discovery
.
Apicco can be also used for request body conversions and formatting. Apicco uses Joi. That is, if the validation convert option is on (enabled by default), a string will be converted using the specified modifiers for string.lowercase(), string.uppercase(), string.trim(), and each replacement specified with string.replace().
The converted request body can be accessed at ctx.request.validatedBody
;
Action files should export the following:
-
validate
A Joi object schema describing the endpoint parameters.
-
handle
An async function that handles the corresponding HTTP request.
//action1.js
const Joi = require('joi');
const validate = {
id: Joi.number().integer().required(),
name: Joi.string().max(256)
};
/*
// OR
const validate = Joi.object({
id: Joi.number().integer().required(),
name: Joi.string().max(256)
});
*/
async function handle({ request, response }) {
response.status = 200;
response.body = {
id: request.body.id,
name: request.body.name
};
}
module.exports = {
validate,
handle
}
- Add Apicco middleware to your Koa app
const Koa = require('koa');
const apicco = require('apicco-lib');
const app = new Koa();
app.use(apicco());
app.listen(3000);
- Create your API action files under the main API folder.
Apicco can be configured via options
parameter. The supported options are:
apiPath
Path to folder containing API resources and action files.
Defaults to ./
prefix
URL prefix for all API endpoints.
Defaults to /api/v1
beforeMiddlewares
An array of Koa middlewares to be executed before Apicco middleware.
Defaults to []
.)
This option can be used for adding authentication or authorization logic to your API. For example, you can add bearer token authentication using passport:
const Koa = require('koa');
const apicco = require('apicco-lib');
const passport = require('koa-passport')
const app = new Koa();
app.use(passport.initialize());
app.use(apicco({
beforeMiddlewares: [passport.authenticate('bearer', { session: false })]
}));
afterMiddlewares
An array of Koa middlewares to be executed after Apicco middleware.
Defaults to []
verbose
Controls route logging during Apicco initialization.
Defaults to false
app/
├── api/
│ ├── movies/
│ | ├── create.js POST /api/movies.create
│ | ├── info.js POST /api/movies.info
│ | ├── list.js => POST /api/movies.list
│ | ├── update.js POST /api/movies.update
| | └── delete.js POST /api/movies.delete
app/
├── api/
│ ├── movies/
│ | ├── create.js POST /api/movies.create
| | ├── listActors.js POST /api/movies.listActors
| | └── addReview.js POST /api/movies.addReview
│ ├── actors/
│ | └── addToMovie.js => POST /api/actors.addToMovie
│ ├── reviews/
│ | └── list.js POST /api/reviews.list
For a complex, production API example please refer to Slack Web API documentation