basilic
v0.0.3-alpha
Published
A minimalist Node.js JSON API with database integration.
Downloads
5
Readme
Basilic (alpha)
A minimalist Node.js JSON API with database integration.
Table of contents
Introduction
Basilic is a minimalist Node.js framework, based on http
package. Its aim is
to provide the minimal things you need to build a functional API, from the
routes to the database.
import basilic, {sqlite} from 'basilic'
const api = basilic
.database(sqlite, ':memory:')
.get('/check', ctx => 204)
.get('/posts', ctx => {
const posts = await sql`SELECT * FROM posts`
return {posts}
})
.listen()
Installation
yarn add basilic
Note: basilic is written in TypeScript, so types are included - no need for
@types
.
Don't forget the driver, depending on your database:
yarn add sqlite3 # For SQLite3
yarn add pg # For PostgreSQL
yarn add mysql # For MySQL
Usage
Database
type database = (BasilicConnector, options?: string) => BasilicServer
basilic.database(connector, ':memory:')
Available connectors:
import {sqlite, postgres, mysql} from 'basilic'
You can also define your own driver (see existing ones):
import {BasilicConnector} from 'basilic'
const custom: BasilicConnector = {
...
}
basilic.database(custom, 'options')
Method
Routes any incomming request to the correct handler. A route matches when the method and the path match:
type get: (Path, Handler) => BasilicServer
type post: (Path, Handler) => BasilicServer
type patch: (Path, Handler) => BasilicServer
type put: (Path, Handler) => BasilicServer
type delete: (Path, Handler) => BasilicServer
api
.get('/route', handler)
.post('/route', handler)
.patch('/route', handler)
.put('/route', handler)
.delete('/route', handler)
Path
A path can be a string or a regular RegExp:
type Path = string | RegExp
api
// Matches only '/route'
.get('/route', handler)
// Matches routes starting by '/route'
.get(/^\/route/, handler)
// You can also use named groups (https://github.com/tc39/proposal-regexp-named-groups)
// Matches '/route/<number>'
// Matched groups are available in ctx.params
.get(/\/route\/(?<id>\d+)/, handler)
Handler
type Handler = BasilicContext => any | void
api
// Returns a 204 without body
.get('/route', ctx => null)
// Returns a 401 without body
.get('/route', ctx => 401)
// Returns a 200 without a JSON body
// Sets automatically Content-Type: application/json
.get('/route', ctx => ({data: 'test'}))
// Returns a 200 without a plain text body
// Sets automatically Content-Type: text/plain
.get('/route', ctx => 'data')
// Returns a 401 with custom headers and data
.get('/route', ctx => ({
status: 401,
headers: {'Content-Type': 'text/plain'},
body: 'data',
}))
Context
type BasilicContext = {
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
url: string
params: any
sql: BasilicConnector['sql']
}
basilic.get('/route', ctx => {
// The matched method
const {method} = ctx
// The matched path
const {url} = ctx
// The matched groups from the path RegExp (if exist)
const {params} = ctx
// The SQL template string helper
// It allows you to easily interact with your database
// All variables inside the template string are escaped
const {sql} = ctx
const value = 'value'
const res = await sql`
SELECT *
FROM table
WHERE attr = ${value}
`
})
Listen
Starts the server:
type listen = (port = 5000, hostname = 'localhost') => void
basilic.listen()
Testing
You can test your API with supertest:
// src/api.ts
import basilic, {sqlite} from 'basilic'
const api = basilic
.database(sqlite, ':memory:')
.get('/route', ctx => 204)
export default api
// src/index.ts
import api from './api'
api.listen()
// src/__tests__/api.ts
import request from 'supertest'
import api from '../api'
const app = api.getListener()
describe('routes', () => {
it('should match route', done => {
request(app)
.get('/route')
.expect(204, done)
})
})
Roadmap
- [ ] Implement middlewares
- [ ] Add auth middleware (JWT)
- [ ] Add SQL migrations
- [ ] Add native connector in context
- [ ] Set up CORS