Quickly create API endpoints using generators/yield, async/await or promises for async operations. Includes file-per-endpoint and reverse-proxy options
From version 1.2 supports responders using async/await from anonymous or named classes as well as generators/yield or promises for async operations.
github see also async-methods
In version 1.1.x Now supports async/await in anonymous or names classes
$nodeserver--config'api-config.js'--port8087constport=8067,apiResponder=require('api-responder')apiResponder('test-api-config',port).then(responder=>{/* responder: { app:<app>, server:<server>, config:<config> }*/}).catch(err=>{})// 'app' already exists in applicationconstapiResponder=require('api-responder')apiResponder('tests/configs/test-api-config',app)// config module.exports={port: 8081,auto: 'endpoints',public: 'tests/public'}// sample directory treeendpointsv1locationcitytype.jsupdatepost.js// auto-generates endpoints:1.get/v1/location/:city/type2.post/v1/location/update/// sample response from http://localhost:8081/v1/location/Paris/type?a=45&b=67{city:Paris} $ npm install api-responder -P
// in external filemodule.exports={apis: [{// Generator based (for async operations)endpoint: "/api/v2/data",responder: function*(){returnyieldPromise.resolve({status: OK,data: 56});}},// or Promise based{endpoint: "/api/v2/test",responder: function*(api,resolve,reject){resolve({status: OK,data: "test"});}}]};- method: 'get'
- CORS: true
- response_status: 200
- public: 'public'
- port: 8081
see /tests/test-app-external-config.js
{method:'get|post|put|etc',// default 'get',endpoint:'/v1/test/location',responder: function(api,resolve,reject){// request data// api.body// api.query// api.cookie// api.params// api.req// settings// api.res// api.response// api.response_status // api.filepath - return file contents// api.attachment - true/false - file as download// api.CORS - true/false// api.headers},{method:'get|post|put|etc',// default 'get',endpoint:'/v1/test/location',responder: function(){letstate=this// request data// state.body// state.query// state.cookie// state.params// state.req// state.headers// settings// state.res.status(404) or// state.response_status = 404// state.filepath - return file// state.attachment - true/false// state.CORS - true/false},or 3a. Class based responders - using async/await (state is passed in context - see generator based responders)
{method:'get|post|put|etc',// default 'get',endpoint: '/testClass',responder: class{constructor(){}asynctestClass(){letstate=thisreturnawaitPromise.resolve({method: 89,headers: state.headers})}},methodName: 'testClass'or 3a. newed-Class based responders - using async/await (an 'api' argument is passed to the responding method definition - see attributes under promise-based responders)
{endpoint: '/testClassObject',responder: newclass{constructor(){}asynctest(api){returnawaitapi.headers}}(),methodName: 'test'}, rproxy:{url:'http://bbc.co.uk',transformRequest:api=>{//optional// change api (eg set api.CORS) or api.rproxy // attributes by reference. // See above for api options},transformResponse:data=>{// optionalreturndata;}}}To use a config either pass a relative path to an extrenal file with module.exports= or pass as an argument to apiResponser eg
apiResponder({port: { ... },public: '...',defaults:{ ... },apis:[ ... ]}){apis:{method:'get|post|put|etc',// default 'get',endpoint:'/v1/test/location',// Promise-basedresponder: function(api,resolve,reject){// request data// api.body// api.query// api.cookie// api.params// api.req// settings// api.res// api.response// api.response_status // api.filepath - return file// api.attachment - true/false// api.CORS - true/false// api.headers},{..},{..}]}{apis: {method:'get|post|put|etc',// default 'get',endpoint:'/v1/location/:city',// or Generator-basedresponder: function(){letstate=this// request data// state.body// state.query// state.cookie// state.params// state.req// state.headers// settings// state.res.status(404) or// state.response_status = 404// state.filepath - return file// state.attachment - true/false// state.CORS - true/false},{..},{..}]}{..public:'dist',..} apis:[{....method:'post',responder: function*(){letstate-this,body=state.body,response// do something async with post bodyreturnresponse}},{....method:'post',responder: (api,resolve)=>{letresponse,body=api.body// do something async with post bodyresolve(responde)}}]{endpoint: '/genparams/:field',responder: function*(){letstate=thisreturnyield{params: state.params,query: state.query}}}localhost:8081//genparams/London?a=456&b=67
returns: {params:{field:'London'},query:{a:456,b:67}}
{endpoint: '/noCORS',CORS: false,responder: function(api,resolve){resolve({test: 67})}},localhost:8081//noCORS
will not have CORS header in response
// returns status code 500{endpoint: '/throw',responder: function*(){letstate=thisthrow{error: 67}returnyieldam({test: 98})}},{endpoint: '/download',responder: function(api,resolve){api.filepath=join(__dirname,'../LeavingEden.mp3')api.type='audio/mpeg'api.attachment=resolve()}}Routing can be fully or partly determined by directory tree. (mix and match with apis:[{..},{..}] configuration)
Specify a top-level directory to hold the paths and specify it in the config as auto:
Default method is get, to configure post, put or head responders use a ../post.sj, ../put.js or ../head.js for the module filenames
// sample directory treeendpointsv1locationcitytype.jsupdatepost.js// auto-generates endpoints:1.get/v1/location/:city/type2.post/v1/location/update/Sample response from http://localhost:8081/v1/location/Paris/type?a=45&b=67
{city:'Paris'}apiResponder({port: 8081,public: 'public',apis:[ ... ]}).addPublic('tests/dist'){endpoint: '/bbc*',rproxy: function(api){return{url: api.req.url.replace('/bbc',''),baseURL: 'http://bbc.co.uk'}}{// change method in reverse proxy using transformRequestendpoint: '/iplayer*',method: 'POST',rproxy: function(api){return{url: api.req.url,baseURL: 'http://bbc.co.uk'}},transformRequest: function(api){api.meethod='GET'}}{endpoint: '/newsapi/sources',rproxy: {url: 'https://newsapi.org/v2/sources',params: {apiKey: 'c13f0b7040a0461397c250f1c94233d0'}},transformResponse: function*(data){returnyielddata.sources}} $ node server
Uses port, public folder and api config set in server.js
[router] Responder listening on port 8081
[router] Static files in /Users/stephen/projects/github/api-responder/public
1. get /v1/location/:city/type
2. post /v1/location/update/
$ node server --config tests/configs/test-api-config.js --port 5000 --public './'
Sets port to 5000 sets public directory to current and uses api config file tests/configs/test-api-config.js
[router] Responder listening on port 5000
[router] Static files in /Users/stephen/projects/github/api-responder/
1. GET /test
2. GET /testClass
3. GET /testClassObject
4. GET /testClassConstructor
5. GET /noCORS
..
..
There are automated tests for all the above features
$ npm test
# or
$ mocha tests
# or
$ nyc mocha tests