Full Code of hiowenluke/noapi for AI

master 1b674c17c886 cached
72 files
30.1 KB
11.5k tokens
21 symbols
1 requests
Download .txt
Repository: hiowenluke/noapi
Branch: master
Commit: 1b674c17c886
Files: 72
Total size: 30.1 KB

Directory structure:
gitextract_cri7q73q/

├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── examples/
│   ├── 01-hello-world/
│   │   ├── biz/
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       └── hi.js
│   │   └── index.js
│   ├── 02-complex-url-params/
│   │   ├── biz/
│   │   │   └── foo/
│   │   │       └── bar.js
│   │   └── index.js
│   ├── 03-returning-an-error/
│   │   ├── biz/
│   │   │   └── do/
│   │   │       └── somethingIsWrong.js
│   │   └── index.js
│   ├── 04-throwing-an-error/
│   │   ├── biz/
│   │   │   └── do/
│   │   │       └── say/
│   │   │           └── hi.js
│   │   └── index.js
│   ├── 05-api-directory/
│   │   ├── api/
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       └── hi.js
│   │   ├── biz/
│   │   │   ├── __lib/
│   │   │   │   └── reverse.js
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       ├── __lib/
│   │   │       │   ├── decode.js
│   │   │       │   └── encode.js
│   │   │       └── hi.js
│   │   └── index.js
│   ├── 06-with-database/
│   │   ├── biz/
│   │   │   ├── about.js
│   │   │   └── user/
│   │   │       ├── get.js
│   │   │       ├── kill.js
│   │   │       ├── list.js
│   │   │       ├── login.js
│   │   │       ├── logout.js
│   │   │       └── register.js
│   │   ├── db/
│   │   │   └── index.js
│   │   └── index.js
│   ├── 07-static-resources/
│   │   ├── biz/
│   │   │   └── about.js
│   │   ├── index.js
│   │   └── public/
│   │       ├── images/
│   │       │   └── 1.jsx
│   │       ├── index.html
│   │       └── nav/
│   │           ├── index.html
│   │           └── main.html
│   ├── 99-options/
│   │   ├── config.js
│   │   ├── index.js
│   │   └── src/
│   │       └── about.js
│   └── noapi.js
├── index.js
├── package.json
├── src/
│   ├── biz/
│   │   ├── do.js
│   │   ├── index.js
│   │   └── paramsCache.js
│   ├── config.js
│   ├── data.js
│   ├── index.js
│   └── server/
│       ├── cross.js
│       ├── index.js
│       ├── public/
│       │   ├── index.js
│       │   └── mime.js
│       └── routes/
│           ├── index.js
│           └── parseQueryStr.js
└── test/
    ├── forExamples/
    │   ├── index.js
    │   └── testCases/
    │       ├── 01-hello-world.js
    │       ├── 02-complex-url-params.js
    │       ├── 03-returning-an-error.js
    │       ├── 04-throwing-an-error.js
    │       ├── 05-api-directory.js
    │       ├── 06-with-database.js
    │       ├── 07-static-resources.js
    │       └── 99-options.js
    ├── index.js
    └── tests/
        ├── api-folder/
        │   ├── api/
        │   │   └── about.js
        │   ├── index.js
        │   └── test/
        │       └── cases.js
        ├── default/
        │   ├── biz/
        │   │   ├── get.js
        │   │   └── post.js
        │   ├── index.js
        │   └── test/
        │       └── cases.js
        └── index.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true


# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,jsx,html,sass}]
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true


================================================
FILE: .gitignore
================================================
node_modules/
module_test/
coverage/
.DS_Store
.idea
package-lock.json
.temp/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Owen Luke

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================

# Noapi

A high-performance and easy-to-use web API framework for [Node.js](https://nodejs.org). Noapi loads directory "biz" as a web API server, each file in it defines and handles an API, so that you can focus on writing business function code. Noapi is simple enough that you just take it "out of the box".

## Install

```sh
npm install noapi --save
```

## TRY IT! (in under 3 minutes)

### 0. Initialize a demo project

```sh
mkdir ./noapi-demo && cd ./noapi-demo
npm init -y
npm install noapi --save
```

Create the core directory "**biz**"

```sh
mkdir biz
```

### 1. Create a biz file

Create file "./biz/say/hi.js". It defines an api "/say/hi" and handles it. 

```js
module.exports = async (name, age) => {
    return {msg: `Hi, I am ${name}, ${age} years old.`};
};
```

### 2. Create index.js

```js
require('noapi')();
```

### 3. Run

```sh
node index.js
Server default is listening on port 3000
```

Visit the url [http://localhost:3000/say/hi?age=100&name=owen]() to see the result:

```json
{
    "success": true,
    "data": {
        "msg": "Hi, I am owen, 100 years old."
    }
}
```

The order of the parameters in the url can be arbitrary.

## Examples

* [01 hello world](./examples/01-hello-world)
* [02 complex url params](./examples/02-complex-url-params)
* [03 returning an error](./examples/03-returning-an-error)
* [04 throwing an error](./examples/04-throwing-an-error)
* [05 api directory](./examples/05-api-directory)
* [06 with database](./examples/06-with-database)
* [07 static resources](./examples/07-static-resources)
* [99 options](./examples/99-options)

## Options

It can be omitted if it is the default value as below. 

```js
const name = 'default';
const dir = './biz';
const host = 'localhost';
const port = 3000; 
const isSilence = false;

// The number and order of parameters can be arbitrary
noapi(name, dir, host, port, isSilence);

// It is equivalents to:
//     const options = {
//         name: 'default',
//         dir: './biz',
//         host: 'localhost',
//         port: 3000,
//         isSilence: true,
//     };
//
//     noapi(options);
```

See "[examples/99-options](./examples/99-options)" to learn about it.

## Biz directory

Each file in the biz directory defines and handles an API. All files in the biz directory make up the API list.

```js
/root
    /biz
        /say
            hi.js       // api: /say/hi
        about.js        // api: /about
     
    index.js    
```

If there are some non-api files (only be used internally) in the biz directory, this will make the API list unclear. Then you should use the **api directory**, just create an empty file (or with the description of this api) to define an api. See "[examples/05-api-directory](./examples/05-api-directory)".

```js
/root
    /api
        /say
            hi.js       // api: /say/hi
        about.js        // api: /about

    /biz
        /__lib
        /say
            /__lib
            hi.js   
            tools.js    // non-api
            check.js    // non-api
        about.js       
        init.js         // non-api
        
    index.js
```

## Performance

Noapi is a high-performance web API framework, faster than [Koa](https://github.com/koajs/koa), [Express](https://github.com/expressjs/express). See [API Framework Performance PK](https://github.com/hiowenluke/api-frameworks-performance-pk)

## Test

```sh
git clone https://github.com/hiowenluke/noapi
cd noapi
npm install
npm test
```

## License

[MIT](LICENSE)

Copyright (c) 2019, Owen Luke


================================================
FILE: examples/01-hello-world/biz/about.js
================================================

// Test
// http://localhost:3000/about

// Result
//		{
// 			"success": true,
// 			"data": {
//				"version": "1.0.0"
// 			}
// 		}

const fn = async () => {
	return {version: '1.0.0'};
};

module.exports = fn;


================================================
FILE: examples/01-hello-world/biz/say/hi.js
================================================

// Test
// http://localhost:3000/say/hi?age=100&name=owen

// Result
// 		{
// 			"success": true,
// 			"data": {
// 				"msg": "Hi, I am owen, 100 years old."
// 			}
// 		}

// The order of the function parameters does NOT have to be
// the same as the order of the url parameters.
const fn = async (name, age) => {
	return {msg: `Hi, I am ${name}, ${age} years old.`};
};

module.exports = fn;


================================================
FILE: examples/01-hello-world/index.js
================================================

require('../noapi')();


================================================
FILE: examples/02-complex-url-params/biz/foo/bar.js
================================================

// Test
// http://localhost:3000/foo/bar?name=owen&obj={"date":"2019-05-01"}&arr=[1,"abc",{"tel":12345678}]

// Result
// 		{
// 			"success": true,
// 			"data": {
// 				"name": "owen",
// 				"obj": {
// 					"date": "2019-05-01"
// 				},
// 				"arr": [
// 					1,
// 					"abc",
// 					{
// 						"tel": 12345678
// 					}
// 				]
// 			}
// 		}

const fn = async (name, obj, arr) => {
	return {name, obj, arr};
};

module.exports = fn;


================================================
FILE: examples/02-complex-url-params/index.js
================================================

require('../noapi')();


================================================
FILE: examples/03-returning-an-error/biz/do/somethingIsWrong.js
================================================

// Test
// http://localhost:3000/do/somethingIsWrong

// Result
// 		{
// 			"success": false,
// 			"error": "something is wrong"
// 		}

const fn = async () => {
	return {error: 'something is wrong'};
};

module.exports = fn;


================================================
FILE: examples/03-returning-an-error/index.js
================================================

require('../noapi')();


================================================
FILE: examples/04-throwing-an-error/biz/do/say/hi.js
================================================

// Test
// http://localhost:3000/do/say/hi

const fn = async () => {
	throw new Error('something is wrong');
};

module.exports = fn;


================================================
FILE: examples/04-throwing-an-error/index.js
================================================

require('../noapi')();


================================================
FILE: examples/05-api-directory/api/about.js
================================================

// This file can be empty, or with the description of this api.
// See ./say/hi.js


================================================
FILE: examples/05-api-directory/api/say/hi.js
================================================
/**
 * @test
 	http://localhost:3000/say/hi?age=100&name=owen

 * @returns
	{
		"success": true,
		"data": {
			"msg": "Hi, I am owen, 100 years old.",
			"reversed": ".dlo sraey 001 ,newo ma I ,iH",
			"encoded": "SGksIEkgYW0gb3dlbiwgMTAwIHllYXJzIG9sZC4="
		}
	}

 * @param {String} 	name 	user's name with a maximum length of 32
 * @param {Integer} age		user's age with a maximum of 200
 * */


================================================
FILE: examples/05-api-directory/biz/__lib/reverse.js
================================================

const fn = (str) => {
	return str.split("").reverse().join("");
};

module.exports = fn;


================================================
FILE: examples/05-api-directory/biz/about.js
================================================

const fn = async () => {
	return {version: '1.0.0'};
};

module.exports = fn;


================================================
FILE: examples/05-api-directory/biz/say/__lib/decode.js
================================================

const fn = (b64Encoded) => {
	return Buffer.from(b64Encoded, 'base64').toString();
};

module.exports = fn;


================================================
FILE: examples/05-api-directory/biz/say/__lib/encode.js
================================================

const fn = (str) => {
	return Buffer.from(str).toString('base64');
};

module.exports = fn;


================================================
FILE: examples/05-api-directory/biz/say/hi.js
================================================

const reverse = require('../__lib/reverse');
const encode = require('./__lib/encode');

const fn = async (name, age) => {
	const msg = `Hi, I am ${name}, ${age} years old.`;
	const reversed = reverse(msg);
	const encoded = encode(msg);

	return {msg, reversed, encoded};
};

module.exports = fn;


================================================
FILE: examples/05-api-directory/index.js
================================================

require('../noapi')();


================================================
FILE: examples/06-with-database/biz/about.js
================================================

// Test
// http://localhost:3000/about

// Result
//		{
// 			"success": true,
// 			"data": {
//				"version": "1.0.0"
// 			}
// 		}

const fn = async () => {
	return {version: '1.0.0'};
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/get.js
================================================

// Test url
// http://localhost:3000/user/get?username=owen

const db = require('../../db');

const fn = async (username) => {
	return await db.user.select(username);
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/kill.js
================================================

// Test url
// http://localhost:3000/user/kill?username=owen

const db = require('../../db');

const fn = async (username) => {
	return await db.user.delete(username);
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/list.js
================================================

// Test url
// http://localhost:3000/user/list

const db = require('../../db');

const fn = async () => {
	return await db.user.select();
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/login.js
================================================

// Test url
// http://localhost:3000/user/login?username=owen&password=123

const db = require('../../db');

const fn = async (username, password) => {
	const result = await db.user.update({username, password}, {isOnline: 1});
	return !!result;
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/logout.js
================================================

// Test url
// http://localhost:3000/user/logout?username=owen

const db = require('../../db');

const fn = async (username) => {
	const result = await db.user.update(username, {isOnline: 0});
	return !!result;
};

module.exports = fn;


================================================
FILE: examples/06-with-database/biz/user/register.js
================================================

// Test url
// http://localhost:3000/user/register?username=owen&password=123

const db = require('../../db');

const fn = async (username, password) => {
	return await db.user.insert({username, password});
};

module.exports = fn;


================================================
FILE: examples/06-with-database/db/index.js
================================================

const data = {
	user: [
		{
			id: 1,
			username: 'admin',
			password: '123456',
			isOnline: 0,
		}
	]
};

// Fake database
const db = {
	user: {
		async insert(userInfo) {
			const id = data.user.length + 1;

			userInfo.isOnline = 0;
			userInfo.id = id;
			data.user.push(userInfo);

			return id;
		},

		async update(where, filedValues) {
			const userInfo = await this.select(where);
			if (!userInfo) {
				return 0;
			}

			const keys = Object.keys(filedValues);
			keys.forEach(key => {
				userInfo[key] = filedValues[key];
			});

			return 1;
		},

		async delete(where) {
			const userInfoId = await this.select(where, true);
			if (userInfoId) {
				data.user.splice(userInfoId - 1, 1);
				return 1;
			}

			return 0;
		},

		async select(where, isReturnId) {
			if (!where) {
				return data.user;
			}
			else {
				if (typeof where === 'string') {
					where = {username: where};
				}

				const whereKeys = Object.keys(where);
				const userInfo = data.user.find(item => {
					const index = whereKeys.findIndex(key => where[key] !== item[key]);
					if (index === -1) {
						return item;
					}
				});

				if (userInfo) {
					return isReturnId ? userInfo.id : userInfo;
				}
				else {
					return null;
				}
			}
		}
	}
};

module.exports = db;


================================================
FILE: examples/06-with-database/index.js
================================================

require('../noapi')();


================================================
FILE: examples/07-static-resources/biz/about.js
================================================

// Test
// http://localhost:3000/about

// Result
//		{
// 			"success": true,
// 			"data": {
//				"version": "1.0.0"
// 			}
// 		}

const fn = async () => {
	return {version: '1.0.0'};
};

module.exports = fn;


================================================
FILE: examples/07-static-resources/index.js
================================================

require('../noapi')();


================================================
FILE: examples/07-static-resources/public/images/1.jsx
================================================
// File type .jsx is not supported


================================================
FILE: examples/07-static-resources/public/index.html
================================================
Hello, world!


================================================
FILE: examples/07-static-resources/public/nav/index.html
================================================
/nav/index.html


================================================
FILE: examples/07-static-resources/public/nav/main.html
================================================
/nav/main.html


================================================
FILE: examples/99-options/config.js
================================================

module.exports = {
	name: 'myApi',
	dir: './src',
	host: '127.0.0.1',
	port: 3001,
	isSilence: true,
};


================================================
FILE: examples/99-options/index.js
================================================

const noapi = require('../noapi');
const config = require('./config');

noapi(config);


================================================
FILE: examples/99-options/src/about.js
================================================

// Test
// http://localhost:3001/about

// Result
//		{
// 			"success": true,
// 			"data": {
//				"version": "1.0.0"
// 			}
// 		}

const fn = async () => {
	return {version: '1.0.0'};
};

module.exports = fn;


================================================
FILE: examples/noapi.js
================================================

module.exports = require('..');


================================================
FILE: index.js
================================================

module.exports = require('./src');


================================================
FILE: package.json
================================================
{
  "name": "noapi",
  "version": "2.2.2",
  "description": "A high-performance and easy-to-use web API framework for Node.js. Noapi loads directory \"biz\" as a web API server, each file in it defines and handles an API, so that you can focus on writing business function code. Noapi is simple enough that you just take it \"out of the box\".",
  "main": "index.js",
  "scripts": {
    "test": "node test"
  },
  "keywords": [
    "node.js",
    "api",
    "microservices",
    "microservices framework"
  ],
  "author": "hi.owen.luke@gmail.com",
  "license": "MIT",
  "dependencies": {
    "caller": "^1.0.1",
    "kdo": "^1.8.1",
    "keypaths": "^0.1.4",
    "lodash": "^4.17.15",
    "qs": "^6.9.1"
  },
  "devDependencies": {
    "testor": "^0.6.5"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/hiowenluke/noapi.git"
  },
  "bugs": {
    "url": "https://github.com/hiowenluke/noapi/issues"
  },
  "homepage": "https://github.com/hiowenluke/noapi#readme"
}


================================================
FILE: src/biz/do.js
================================================

const paramsCache = require('./paramsCache');
const data = require('../data');
const keyPaths = require('keypaths');

const fn = async (api, query) => {
	const apiX = data.apisX[api]; // "/say/hi" => "say.hi"
	const func = keyPaths.get(data.handlers, apiX); // say.hi()

	if (typeof func !== 'function') {
		return {error: `The handler ./biz${api}.js does not exists.`};
	}

	const names = paramsCache.getByApi(api);
	const args = names.map(name => query[name]);

	const result = await func(...args);
	return result;
};

module.exports = fn;


================================================
FILE: src/biz/index.js
================================================

const paramsCache = require('./paramsCache');

const me = {
	init() {
		paramsCache.init();
	}
};

module.exports = me;


================================================
FILE: src/biz/paramsCache.js
================================================

const fs = require('fs');
const data = require('../data');
const config = require('../config');

const parseParamsNames = (str) => { // "(a, b = '', c) => {}"
	const temp = str.match(/\((.*?)\)/); // "a, b = '', c"
	if (!temp) return null;

	const params = temp[1].split(','); // ['a', " b = ''", ' c']
	const names = params.map(item => item.replace(/(^\s*?(?=\b))|(\s*?$)/g, '').split('=')[0]); // ['a', 'b', 'c']

	return names;
};

const me = {
	data: {},

	init() {
		const root = config.webServiceRoot;
		const bizDir = config.dir.replace(/^./, ''); // ./biz => /biz
		const apis = data.apis;

		apis.forEach(api => {
			let filePath = root + bizDir + api;

			// The filePath will be exists if it is a directory
			if (!fs.existsSync(filePath)) {

				// If it it not exists, then check for .js file
				filePath += '.js';

				// If not found, then ignore it
				if (!fs.existsSync(filePath)) return;
			}

			// Require the directory or js file
			const bizFile = require(filePath);
			const content = bizFile.toString(); // "(a, b = '', c) => {}"

			const names = parseParamsNames(content);
			this.data[api] = names;
		});
	},

	getByApi(api) {
		return this.data[api] || [];
	}
};

module.exports = me;


================================================
FILE: src/config.js
================================================

const fs = require('fs');
const path = require('path');

const me = {
	name: 'default',
	dir: './biz',
	host: 'localhost',
	port: 3000,
	isSilence: false, // Do not print logs if it is true

	// 0 print "Internal Server Error"
	// 1 print error message and stack 1
	// 2 print full error stack
	onerror: 1,

	webServiceRoot: '', // The root path of web service
	enablePublic: '', // Enable public if the directory "public" is exists

	init(pathToCaller, args = []) {
		this.webServiceRoot = path.resolve(pathToCaller, '..');
		this.enablePublic = fs.existsSync(this.webServiceRoot + '/public');

		let name, dir, host, port, isSilence;

		if (typeof args[0] === 'object') {
			({name, dir, host, port, isSilence} = args[0]);
		}
		else {
			args.forEach(arg => {
				if (!arg) return;

				const type = typeof arg;
				if (type === 'number') {
					port = arg;
				}
				else if (type === 'boolean') {
					isSilence = arg;
				}
				else if (type === 'string') {
					if (arg.substr(0, 1) === '.') {
						dir = arg;
					}
					else if (arg !== 'localhost' && arg.indexOf('.') === -1) {
						name = arg;
					}
					else {
						host = arg;
					}
				}
			});
		}

		name && (this.name = name);
		dir && (this.dir = dir);
		host && (this.host = host);
		port && (this.port = port);
		isSilence && (this.isSilence = isSilence);
	},
};

module.exports = me;


================================================
FILE: src/data.js
================================================

const fs = require('fs');
const path = require('path');
const kdo = require('kdo');

const config = require('./config');
const keyPaths = require('keypaths');

const loadFolder = (folderName) => {
	let obj;

	const root = config.webServiceRoot;
	const folderPath = path.resolve(root + '/' + folderName);

	if (fs.existsSync(folderPath)) {
		const indexJs = folderPath + '/index.js';

		if (fs.existsSync(indexJs)) {
			obj = require(folderPath);
		}
		else {
			const simulateIndexJs = {filename: indexJs};
			obj = kdo(simulateIndexJs);
		}
	}

	return obj;
};

const loadFolders = () => {
	const core = {};
	const bizDirName = config.dir.replace(/^.\//, ''); // ./biz => biz

	core.api = loadFolder('api');
	core.biz = loadFolder(bizDirName);

	const obj = core.api || core.biz || {};
	const apiPaths = keyPaths.toPaths(obj); // ["say.hi"]

	// "say.hi" => "/say/hi"
	const apis = apiPaths.map(item => '/' + item.replace(/\./g, '/'));

	const apisX = {};

	// {"/say/hi": "say.hi"}
	apis.forEach((api, index) => {apisX[api] = apiPaths[index]});

	return {apis, apisX, handlers: core.biz};
};

const me = {
	apis: [], // ["/say/hi"]
	aha: {}, // {"/say/hi": "say.hi"}
	handlers: {}, // {say: {hi: f()}}

	init() {
		const {apis, apisX, handlers} = loadFolders();

		this.apis = apis;
		this.apisX = apisX;
		this.handlers = handlers;
	},
};

module.exports = me;


================================================
FILE: src/index.js
================================================

const caller = require('caller');
const config = require('./config');

const data = require('./data');
const biz = require('./biz');
const server = require('./server');

const fn = (...args) => {
	config.init(caller(), args);

	data.init();
	biz.init();

	server.start();
};

module.exports = fn;


================================================
FILE: src/server/cross.js
================================================

const fn = (res) => {

	// Website you wish to allow to connect
	res.setHeader('Access-Control-Allow-Origin', '*');

	// Request methods you wish to allow
	res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

	// Request headers you wish to allow
	res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

	// Set to true if you need the website to include cookies in the requests sent
	// to the API (e.g. in case you use sessions)
	res.setHeader('Access-Control-Allow-Credentials', true);
};

module.exports = fn;


================================================
FILE: src/server/index.js
================================================

const http = require('http');

const config = require('../config');
const routes = require('./routes');
const processPublic = require('./public');

const done = (res, result) => {
	if (typeof result === 'undefined') {
		result = {success: false, error: "Internal Server Error"};
	}
	else if (result && result.error) {
		result = {success: false, error: result.error};
	}
	else {
		result = {success: true, data: result};
	}

	write(res, 'json', JSON.stringify(result));
};

const write = (res, type, str) => {
	const types = {
		json: 'application/json',
		html: 'text/html',
	};

	if (type === 'html' && !/^<html>/i.test(str)) {
		str = `<html><body>${str}</body></html>`;
	}

	res.writeHead(200, {'Content-Type': types[type], 'X-Powered-By': 'Noapi'});
	res.write(str);
	res.end();
};

const getQueryStr = (req) => {
	return new Promise(resolve => {
		let str = '';

		req.on('data', (chunk) => {
			str += chunk;
		});

		req.on('end',()=>{
			resolve(str);
		});
	})
};

const getErrorMessages = (arr) => {
	const messages = [];

	arr.forEach(a => {
		if (a.substr(0, 7 ) !== '    at ') {
			messages.push(a);
		}
	});

	return messages;
};

const me = {
	start() {
		const server = new http.Server();
		server.on('request',async (req, res) => {
			const url = req.url;
			let [api, queryStr] = url.split('?');

			if (config.enablePublic) {
				const done = processPublic(api, res);
				if (done) return;
			}
			else {
				if (api === '/favicon.ico') {
					return done(res, null);
				}

				if (api === '/') {
					return done(res, 'Welcome to Noapi.');
				}
			}

			const method = req.method.toLowerCase();
			if (method === 'post') {
				queryStr = await getQueryStr(req);
			}

			try {
				let result = await routes(api, queryStr);

				if (result && result.error) {
					!config.isSilence && console.log(result.error);
				}

				done(res, result);
			}
			catch(e) {
				const onerror = config.onerror;
				!config.isSilence && console.log(e);

				if (onerror === 0) {
					done(res);
				}
				else {
					const arr = e.stack.split('\n');

					// print error message with stack 1
					if (onerror === 1) {
						const messages = getErrorMessages(arr);
						const message = messages.join('\n');
						let script = arr.find(a => a.substr(0, 7) === '    at ');
						script = script
							.replace('    at fn (', '')
							.replace(config.webServiceRoot, '.')
							.replace(/\)$/, '')
						;
						done(res, {error: {message, script}});
					}
					else {
						// print full error stack
						let str = arr.join('<br/>');
						str = str.replace(/ {4}/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
						write(res, 'html', str);
					}
				}
			}
		});

		const {name, host, port, isSilence} = config;
		server.listen(port, () => {
			if (isSilence) return;
			console.log(`Server ${name} running at http://${host}:${port}`);
		});
	}
};

module.exports = me;


================================================
FILE: src/server/public/index.js
================================================

const fs = require('fs');
const path = require('path');

const config = require('../../config');
const mime = require('./mime');

function readFile(filePath, contentType, res) {
	res.writeHead(200, { 'content-type': contentType });

	const stream = fs.createReadStream(filePath);
	stream.on('error', () => {
		res.writeHead(500, { 'content-type': contentType });
		res.end('<h1>500 Server Error</h1>')
	});

	stream.pipe(res);
}

const response = (res, html) => {
	res.writeHead(200, { 'content-type': 'text/html' });
	res.end(html);
};

const getFilePath = (pathName) => {
	return path.resolve(config.webServiceRoot + '/public' + pathName);
};

const fn = (pathName, res) => {
	if (pathName === '/') {
		pathName = '/index.html';
	}

	let ext = path.extname(pathName);
	ext = ext ? ext.slice(1) : '';

	// non-static resources
	const contentType = mime[ext];
	if (!contentType) {

		const filePath = getFilePath(pathName);
		if (fs.existsSync(filePath)) {

			// It is a directory
			if (fs.statSync(filePath).isDirectory()) {
				const index = filePath + '/index.html';

				// no index.html
				if (!fs.existsSync(index)) {
					response(res, 'Directory listing is not supported');
				}
				else {
					// load index.html
					readFile(index, mime['html'], res);
				}
			}
			else {
				// It is a file
				// That means its file type is not be supported
				response(res, 'File type .' + ext + ' is not supported');
			}

			return true;
		}
		else {
			// It is an api, then do nothing
			return false;
		}
	}

	const filePath = getFilePath(pathName);
	if (!fs.existsSync(filePath)) {
		// not found
		response(res, pathName + ' is not found');
	}
	else {
		// static resources
		readFile(filePath, contentType, res);
	}

	return true;
};

module.exports = fn;



================================================
FILE: src/server/public/mime.js
================================================

const me = {
	css: 'text/css',
	gif: 'image/gif',
	html: 'text/html',
	ico: 'image/x-icon',
	jpeg: 'image/jpeg',
	jpg: 'image/jpeg',
	js: 'text/javascript',
	json: 'application/json',
	pdf: 'application/pdf',
	png: 'image/png',
	svg: 'image/svg+xml',
	swf: 'application/x-shockwave-flash',
	tiff: 'image/tiff',
	txt: 'text/plain',
	wav: 'audio/x-wav',
	wma: 'audio/x-ms-wma',
	wmv: 'video/x-ms-wmv',
	xml: 'text/xml'
};

module.exports = me;


================================================
FILE: src/server/routes/index.js
================================================

const config = require('../../config');
const data = require('../../data');
const bizDo = require('../../biz/do');
const parseQueryStr = require('./parseQueryStr');

const fn = async (api, queryStr) => {

	const isApiExists = data.apis.indexOf(api) >= 0;
	if (!isApiExists) {
		return {error: `${api} is not found`};
	}

	const query = parseQueryStr.do(queryStr);
	if (query && query.error) {
		return query;
	}

	const result = await bizDo(api, query);
	return result;
};

module.exports = fn;


================================================
FILE: src/server/routes/parseQueryStr.js
================================================

const url  = require('url');
const qs = require('qs');

const parseQueryStr = (str) => {
	let query;
	let errArg;
	let isComplexQueryStr;

	try {
		// From post
		// name=owen&obj%5Bdate%5D=2019-05-01&arr%5B0%5D=1&arr%5B1%5D=abc&arr%5B2%5D%5Btel%5D=12345678
		if (/(^|&).+?\b((%5B)|(\[))/.test(str)) {
			isComplexQueryStr = 1;
			query = qs.parse(str);
		}
		else {
			// From get
			// name=owen&obj={%22date%22:%222019-05-01%22}&arr=[1,%22abc%22,{%22tel%22:12345678}]

			// Simulate a complete url-string so that we can use url.parse() to parse it
			query = url.parse('/?' + str, true).query;

			const keys = Object.keys(query);
			keys.forEach(key => {
				const val = query[key];
				if (!/[[{]/.test(val)) return;

				errArg = key;

				// Processes only standard json strings, regardless of object.
				query[key] = JSON.parse(val);
			});
		}
	}
	catch(e) {
		console.log(e);

		if (isComplexQueryStr) {
			query = {error: `${str} has invalid json string.`}
		}
		else {
			query = {error: `${errArg} is an invalid json string.`}
		}
	}

	return query;
};


const me = {
	cache: {},

	do(queryStr) {
		if (!queryStr) {
			return {};
		}

		if (!this.cache[queryStr]) {
			const query = parseQueryStr(queryStr);
			if (query && query.error) {
				return query;
			}

			// ECMAScript 2016 (ed. 7) established a maximum length of 2^53 - 1 elements
			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length
			this.cache[queryStr] = query;
		}

		return this.cache[queryStr];
	},
};

module.exports = me;


================================================
FILE: test/forExamples/index.js
================================================

const fs = require('fs');
const path = require('path');
const cp = require('child_process');

const main = () => {
	const testorPath = path.resolve(__dirname, '../../node_modules/testor/bin/testor');
	const examplesPath = path.resolve(__dirname, '../../examples');
	const testCasesPath = path.resolve(__dirname, './testCases');

	const exampleNames = fs.readdirSync(examplesPath);
	exampleNames.forEach(exampleName => {
		if (exampleName.substr(0, 1) === '.') return;

		const examplePath = examplesPath + '/' + exampleName;
		if (!fs.statSync(examplePath).isDirectory()) return;

		const exampleTestPath = examplePath + '/test';
		const targetCasesFile = exampleTestPath + '/cases.js';

		fs.mkdirSync(exampleTestPath);
		fs.copyFileSync(testCasesPath + '/' + exampleName + '.js', targetCasesFile);

		const args = [testorPath, examplePath];
		const userConfigFile = fs.existsSync(examplePath + '/config.js') ? '--config' : '';
		if (userConfigFile) args.push(userConfigFile);

		cp.spawnSync('node', args, {stdio: "inherit"});

		fs.unlinkSync(exampleTestPath + '/cases.js');
		fs.rmdirSync(exampleTestPath);
	});
};

main();


================================================
FILE: test/forExamples/testCases/01-hello-world.js
================================================

const me = [

	'/say/hi',
	{
		params: {
			name: 'owen',
			age: 100
		},

		result: {
			success: true,
			data: {
				msg: "Hi, I am owen, 100 years old."
			}
		}
	},

	'/about',
	{
		result: {
			success: true,
			data: {
				"version": "1.0.0"
			}
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/02-complex-url-params.js
================================================

const me = [

	'/foo/bar',
	{
		params: {
			name: "owen",
			obj: {
				date: "2019-05-01"
			},
			arr: [
				1,
				"abc",
				{
					tel: 12345678
				}
			]
		},

		result: {
			success: true,
			data: {
				"name": "owen",
				"obj": {
					"date": "2019-05-01"
				},
				"arr": [
					"1",
					"abc",
					{
						"tel": "12345678"
					}
				]
			}
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/03-returning-an-error.js
================================================

const me = [

	'/do/somethingIsWrong',
	{
		result: {
			success: false,
			error: "something is wrong"
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/04-throwing-an-error.js
================================================

const me = [

	'/do/say/hi',
	{
		verify(result) {
			return result.error.message.indexOf('something is wrong') >= 0;
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/05-api-directory.js
================================================

const me = [

	'/say/hi',
	{
		params: {
			name: 'owen',
			age: 100
		},

		result: {
			"success": true,
			"data": {
				"msg": "Hi, I am owen, 100 years old.",
				"reversed": ".dlo sraey 001 ,newo ma I ,iH",
				"encoded": "SGksIEkgYW0gb3dlbiwgMTAwIHllYXJzIG9sZC4="
			}
		}
	},

	'/about',
	{
		result: {
			success: true,
			data: {
				"version": "1.0.0"
			}
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/06-with-database.js
================================================

const me = [

	'/user/login?username=owen&password=123',
	{
		before: [
			'/user/register?username=owen&password=123',
		],

		after: [
			'/user/kill?username=owen',
		],

		verify(result) {
			return result.data === true;
		}
	},

	'/user/logout?username=owen',
	{
		before: [
			'/user/register?username=owen&password=123',
			'/user/login?username=owen&password=123',
		],

		resultUrl: '/user/get?username=owen',

		after: [
			'/user/kill?username=owen',
		],

		verify(result) {
			return result.data.isOnline === 0;
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/07-static-resources.js
================================================

const me = [

	'/',
	{
		verify(result) {
			return result.indexOf('Hello, world!') >= 0;
		}
	},

	'/images',
	{
		verify(result) {
			return result.indexOf('Directory listing is not supported') >= 0;
		}
	},

	'/images/1.jsx',
	{
		verify(result) {
			return result.indexOf('File type .jsx is not supported') >= 0;
		}
	},

	'/images/guitar.png',
	{
		verify(result) {
			return result.indexOf('\u0000') >= 0;
		}
	},

	'/nav',
	{
		verify(result) {
			return result.indexOf('/nav/index.html') >= 0;
		}
	},

	'/nav/main.html',
	{
		verify(result) {
			return result.indexOf('/nav/main.html') >= 0;
		}
	},

	'/about',
	{
		success: true,
		data: {
			"version": "1.0.0"
		}
	},
];

module.exports = me;


================================================
FILE: test/forExamples/testCases/99-options.js
================================================

const me = [
	'/about',
	{
		result: {
			success: true,
			data: {
				"version": "1.0.0"
			}
		}
	},
];

module.exports = me;


================================================
FILE: test/index.js
================================================

require('./forExamples');
require('./tests');


================================================
FILE: test/tests/api-folder/api/about.js
================================================

// Test
// http://localhost:3000/about


================================================
FILE: test/tests/api-folder/index.js
================================================

const noapi = require('../../..');
noapi();


================================================
FILE: test/tests/api-folder/test/cases.js
================================================

const me = [
	'/about',
	{
		result: {
			"success": false,
			"error": "The handler ./biz/about.js does not exists."
		}
	},
];

module.exports = me;


================================================
FILE: test/tests/default/biz/get.js
================================================

const fn = async (name, obj, arr) => {
	return {name, obj, arr};
};

module.exports = fn;


================================================
FILE: test/tests/default/biz/post.js
================================================

const fn = async (name, obj, arr) => {
	return {name, obj, arr};
};

module.exports = fn;


================================================
FILE: test/tests/default/index.js
================================================

const noapi = require('../../..');
noapi();


================================================
FILE: test/tests/default/test/cases.js
================================================

const me = [
	'/',
	{
		result: {
			"success": true,
			"data": "Welcome to Noapi."
		}
	},

	'/xxx',
	{
		result: {
			"success": false,
			"error": "/xxx is not found"
		}
	},

	'/get',
	{
		method: 'GET',

		params: {
			"name": "owen",
			"obj": {
				"date": "2019-05-01"
			},
			"arr": [
				1,
				"abc",
				{
					"tel": 12345678
				}
			]
		},

		result: {
			"success": true,
			"data": {
				"name": "owen",
				"obj": {
					"date": "2019-05-01"
				},
				"arr": [
					"1",
					"abc",
					{
						"tel": "12345678"
					}
				]
			}
		}
	},

	'/post',
	{
		method: 'POST',

		params: {
			"name": "owen",
			"obj": {
				"date": "2019-05-01"
			},
			"arr": [
				1,
				"abc",
				{
					"tel": 12345678
				}
			]
		},

		result: {
			"success": true,
			"data": {
				"name": "owen",
				"obj": {
					"date": "2019-05-01"
				},
				"arr": [
					"1",
					"abc",
					{
						"tel": "12345678"
					}
				]
			}
		}
	}
];

module.exports = me;


================================================
FILE: test/tests/index.js
================================================

const fs = require('fs');
const path = require('path');
const cp = require('child_process');

const main = () => {
	const testorPath = path.resolve(__dirname, '../../node_modules/testor/bin/testor');
	const examplesPath = __dirname;
	const exampleNames = fs.readdirSync(examplesPath);

	exampleNames.forEach(exampleName => {
		if (exampleName.substr(0, 1) === '.') return;

		const examplePath = examplesPath + '/' + exampleName;
		if (!fs.statSync(examplePath).isDirectory()) return;

		cp.spawnSync('node', [testorPath, examplePath], {stdio: "inherit"});
	});
};

main();
Download .txt
gitextract_cri7q73q/

├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── examples/
│   ├── 01-hello-world/
│   │   ├── biz/
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       └── hi.js
│   │   └── index.js
│   ├── 02-complex-url-params/
│   │   ├── biz/
│   │   │   └── foo/
│   │   │       └── bar.js
│   │   └── index.js
│   ├── 03-returning-an-error/
│   │   ├── biz/
│   │   │   └── do/
│   │   │       └── somethingIsWrong.js
│   │   └── index.js
│   ├── 04-throwing-an-error/
│   │   ├── biz/
│   │   │   └── do/
│   │   │       └── say/
│   │   │           └── hi.js
│   │   └── index.js
│   ├── 05-api-directory/
│   │   ├── api/
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       └── hi.js
│   │   ├── biz/
│   │   │   ├── __lib/
│   │   │   │   └── reverse.js
│   │   │   ├── about.js
│   │   │   └── say/
│   │   │       ├── __lib/
│   │   │       │   ├── decode.js
│   │   │       │   └── encode.js
│   │   │       └── hi.js
│   │   └── index.js
│   ├── 06-with-database/
│   │   ├── biz/
│   │   │   ├── about.js
│   │   │   └── user/
│   │   │       ├── get.js
│   │   │       ├── kill.js
│   │   │       ├── list.js
│   │   │       ├── login.js
│   │   │       ├── logout.js
│   │   │       └── register.js
│   │   ├── db/
│   │   │   └── index.js
│   │   └── index.js
│   ├── 07-static-resources/
│   │   ├── biz/
│   │   │   └── about.js
│   │   ├── index.js
│   │   └── public/
│   │       ├── images/
│   │       │   └── 1.jsx
│   │       ├── index.html
│   │       └── nav/
│   │           ├── index.html
│   │           └── main.html
│   ├── 99-options/
│   │   ├── config.js
│   │   ├── index.js
│   │   └── src/
│   │       └── about.js
│   └── noapi.js
├── index.js
├── package.json
├── src/
│   ├── biz/
│   │   ├── do.js
│   │   ├── index.js
│   │   └── paramsCache.js
│   ├── config.js
│   ├── data.js
│   ├── index.js
│   └── server/
│       ├── cross.js
│       ├── index.js
│       ├── public/
│       │   ├── index.js
│       │   └── mime.js
│       └── routes/
│           ├── index.js
│           └── parseQueryStr.js
└── test/
    ├── forExamples/
    │   ├── index.js
    │   └── testCases/
    │       ├── 01-hello-world.js
    │       ├── 02-complex-url-params.js
    │       ├── 03-returning-an-error.js
    │       ├── 04-throwing-an-error.js
    │       ├── 05-api-directory.js
    │       ├── 06-with-database.js
    │       ├── 07-static-resources.js
    │       └── 99-options.js
    ├── index.js
    └── tests/
        ├── api-folder/
        │   ├── api/
        │   │   └── about.js
        │   ├── index.js
        │   └── test/
        │       └── cases.js
        ├── default/
        │   ├── biz/
        │   │   ├── get.js
        │   │   └── post.js
        │   ├── index.js
        │   └── test/
        │       └── cases.js
        └── index.js
Download .txt
SYMBOL INDEX (21 symbols across 11 files)

FILE: examples/06-with-database/db/index.js
  method insert (line 16) | async insert(userInfo) {
  method update (line 26) | async update(where, filedValues) {
  method delete (line 40) | async delete(where) {
  method select (line 50) | async select(where, isReturnId) {

FILE: src/biz/index.js
  method init (line 5) | init() {

FILE: src/biz/paramsCache.js
  method init (line 19) | init() {
  method getByApi (line 46) | getByApi(api) {

FILE: src/config.js
  method init (line 20) | init(pathToCaller, args = []) {

FILE: src/data.js
  method init (line 56) | init() {

FILE: src/server/index.js
  method start (line 64) | start() {

FILE: src/server/public/index.js
  function readFile (line 8) | function readFile(filePath, contentType, res) {

FILE: src/server/routes/parseQueryStr.js
  method do (line 54) | do(queryStr) {

FILE: test/forExamples/testCases/04-throwing-an-error.js
  method verify (line 6) | verify(result) {

FILE: test/forExamples/testCases/06-with-database.js
  method verify (line 14) | verify(result) {
  method verify (line 32) | verify(result) {

FILE: test/forExamples/testCases/07-static-resources.js
  method verify (line 6) | verify(result) {
  method verify (line 13) | verify(result) {
  method verify (line 20) | verify(result) {
  method verify (line 27) | verify(result) {
  method verify (line 34) | verify(result) {
  method verify (line 41) | verify(result) {
Condensed preview — 72 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (39K chars).
[
  {
    "path": ".editorconfig",
    "chars": 302,
    "preview": "root = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n\n#"
  },
  {
    "path": ".gitignore",
    "chars": 78,
    "preview": "node_modules/\nmodule_test/\ncoverage/\n.DS_Store\n.idea\npackage-lock.json\n.temp/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2019 Owen Luke\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "README.md",
    "chars": 3521,
    "preview": "\n# Noapi\n\nA high-performance and easy-to-use web API framework for [Node.js](https://nodejs.org). Noapi loads directory "
  },
  {
    "path": "examples/01-hello-world/biz/about.js",
    "chars": 215,
    "preview": "\n// Test\n// http://localhost:3000/about\n\n// Result\n//\t\t{\n// \t\t\t\"success\": true,\n// \t\t\t\"data\": {\n//\t\t\t\t\"version\": \"1.0.0\""
  },
  {
    "path": "examples/01-hello-world/biz/say/hi.js",
    "chars": 399,
    "preview": "\n// Test\n// http://localhost:3000/say/hi?age=100&name=owen\n\n// Result\n// \t\t{\n// \t\t\t\"success\": true,\n// \t\t\t\"data\": {\n// \t"
  },
  {
    "path": "examples/01-hello-world/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/02-complex-url-params/biz/foo/bar.js",
    "chars": 446,
    "preview": "\n// Test\n// http://localhost:3000/foo/bar?name=owen&obj={\"date\":\"2019-05-01\"}&arr=[1,\"abc\",{\"tel\":12345678}]\n\n// Result\n"
  },
  {
    "path": "examples/02-complex-url-params/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/03-returning-an-error/biz/do/somethingIsWrong.js",
    "chars": 229,
    "preview": "\n// Test\n// http://localhost:3000/do/somethingIsWrong\n\n// Result\n// \t\t{\n// \t\t\t\"success\": false,\n// \t\t\t\"error\": \"somethin"
  },
  {
    "path": "examples/03-returning-an-error/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/04-throwing-an-error/biz/do/say/hi.js",
    "chars": 135,
    "preview": "\n// Test\n// http://localhost:3000/do/say/hi\n\nconst fn = async () => {\n\tthrow new Error('something is wrong');\n};\n\nmodule"
  },
  {
    "path": "examples/04-throwing-an-error/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/05-api-directory/api/about.js",
    "chars": 84,
    "preview": "\n// This file can be empty, or with the description of this api.\n// See ./say/hi.js\n"
  },
  {
    "path": "examples/05-api-directory/api/say/hi.js",
    "chars": 395,
    "preview": "/**\n * @test\n \thttp://localhost:3000/say/hi?age=100&name=owen\n\n * @returns\n\t{\n\t\t\"success\": true,\n\t\t\"data\": {\n\t\t\t\"msg\": \""
  },
  {
    "path": "examples/05-api-directory/biz/__lib/reverse.js",
    "chars": 90,
    "preview": "\nconst fn = (str) => {\n\treturn str.split(\"\").reverse().join(\"\");\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "examples/05-api-directory/biz/about.js",
    "chars": 79,
    "preview": "\nconst fn = async () => {\n\treturn {version: '1.0.0'};\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "examples/05-api-directory/biz/say/__lib/decode.js",
    "chars": 109,
    "preview": "\nconst fn = (b64Encoded) => {\n\treturn Buffer.from(b64Encoded, 'base64').toString();\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "examples/05-api-directory/biz/say/__lib/encode.js",
    "chars": 93,
    "preview": "\nconst fn = (str) => {\n\treturn Buffer.from(str).toString('base64');\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "examples/05-api-directory/biz/say/hi.js",
    "chars": 297,
    "preview": "\nconst reverse = require('../__lib/reverse');\nconst encode = require('./__lib/encode');\n\nconst fn = async (name, age) =>"
  },
  {
    "path": "examples/05-api-directory/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/06-with-database/biz/about.js",
    "chars": 215,
    "preview": "\n// Test\n// http://localhost:3000/about\n\n// Result\n//\t\t{\n// \t\t\t\"success\": true,\n// \t\t\t\"data\": {\n//\t\t\t\t\"version\": \"1.0.0\""
  },
  {
    "path": "examples/06-with-database/biz/user/get.js",
    "chars": 193,
    "preview": "\n// Test url\n// http://localhost:3000/user/get?username=owen\n\nconst db = require('../../db');\n\nconst fn = async (usernam"
  },
  {
    "path": "examples/06-with-database/biz/user/kill.js",
    "chars": 194,
    "preview": "\n// Test url\n// http://localhost:3000/user/kill?username=owen\n\nconst db = require('../../db');\n\nconst fn = async (userna"
  },
  {
    "path": "examples/06-with-database/biz/user/list.js",
    "chars": 164,
    "preview": "\n// Test url\n// http://localhost:3000/user/list\n\nconst db = require('../../db');\n\nconst fn = async () => {\n\treturn await"
  },
  {
    "path": "examples/06-with-database/biz/user/login.js",
    "chars": 271,
    "preview": "\n// Test url\n// http://localhost:3000/user/login?username=owen&password=123\n\nconst db = require('../../db');\n\nconst fn ="
  },
  {
    "path": "examples/06-with-database/biz/user/logout.js",
    "chars": 237,
    "preview": "\n// Test url\n// http://localhost:3000/user/logout?username=owen\n\nconst db = require('../../db');\n\nconst fn = async (user"
  },
  {
    "path": "examples/06-with-database/biz/user/register.js",
    "chars": 233,
    "preview": "\n// Test url\n// http://localhost:3000/user/register?username=owen&password=123\n\nconst db = require('../../db');\n\nconst f"
  },
  {
    "path": "examples/06-with-database/db/index.js",
    "chars": 1279,
    "preview": "\nconst data = {\n\tuser: [\n\t\t{\n\t\t\tid: 1,\n\t\t\tusername: 'admin',\n\t\t\tpassword: '123456',\n\t\t\tisOnline: 0,\n\t\t}\n\t]\n};\n\n// Fake d"
  },
  {
    "path": "examples/06-with-database/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/07-static-resources/biz/about.js",
    "chars": 215,
    "preview": "\n// Test\n// http://localhost:3000/about\n\n// Result\n//\t\t{\n// \t\t\t\"success\": true,\n// \t\t\t\"data\": {\n//\t\t\t\t\"version\": \"1.0.0\""
  },
  {
    "path": "examples/07-static-resources/index.js",
    "chars": 24,
    "preview": "\nrequire('../noapi')();\n"
  },
  {
    "path": "examples/07-static-resources/public/images/1.jsx",
    "chars": 35,
    "preview": "// File type .jsx is not supported\n"
  },
  {
    "path": "examples/07-static-resources/public/index.html",
    "chars": 14,
    "preview": "Hello, world!\n"
  },
  {
    "path": "examples/07-static-resources/public/nav/index.html",
    "chars": 16,
    "preview": "/nav/index.html\n"
  },
  {
    "path": "examples/07-static-resources/public/nav/main.html",
    "chars": 15,
    "preview": "/nav/main.html\n"
  },
  {
    "path": "examples/99-options/config.js",
    "chars": 105,
    "preview": "\nmodule.exports = {\n\tname: 'myApi',\n\tdir: './src',\n\thost: '127.0.0.1',\n\tport: 3001,\n\tisSilence: true,\n};\n"
  },
  {
    "path": "examples/99-options/index.js",
    "chars": 88,
    "preview": "\nconst noapi = require('../noapi');\nconst config = require('./config');\n\nnoapi(config);\n"
  },
  {
    "path": "examples/99-options/src/about.js",
    "chars": 215,
    "preview": "\n// Test\n// http://localhost:3001/about\n\n// Result\n//\t\t{\n// \t\t\t\"success\": true,\n// \t\t\t\"data\": {\n//\t\t\t\t\"version\": \"1.0.0\""
  },
  {
    "path": "examples/noapi.js",
    "chars": 33,
    "preview": "\nmodule.exports = require('..');\n"
  },
  {
    "path": "index.js",
    "chars": 36,
    "preview": "\nmodule.exports = require('./src');\n"
  },
  {
    "path": "package.json",
    "chars": 989,
    "preview": "{\n  \"name\": \"noapi\",\n  \"version\": \"2.2.2\",\n  \"description\": \"A high-performance and easy-to-use web API framework for No"
  },
  {
    "path": "src/biz/do.js",
    "chars": 543,
    "preview": "\nconst paramsCache = require('./paramsCache');\nconst data = require('../data');\nconst keyPaths = require('keypaths');\n\nc"
  },
  {
    "path": "src/biz/index.js",
    "chars": 121,
    "preview": "\nconst paramsCache = require('./paramsCache');\n\nconst me = {\n\tinit() {\n\t\tparamsCache.init();\n\t}\n};\n\nmodule.exports = me;"
  },
  {
    "path": "src/biz/paramsCache.js",
    "chars": 1216,
    "preview": "\nconst fs = require('fs');\nconst data = require('../data');\nconst config = require('../config');\n\nconst parseParamsNames"
  },
  {
    "path": "src/config.js",
    "chars": 1361,
    "preview": "\nconst fs = require('fs');\nconst path = require('path');\n\nconst me = {\n\tname: 'default',\n\tdir: './biz',\n\thost: 'localhos"
  },
  {
    "path": "src/data.js",
    "chars": 1365,
    "preview": "\nconst fs = require('fs');\nconst path = require('path');\nconst kdo = require('kdo');\n\nconst config = require('./config')"
  },
  {
    "path": "src/index.js",
    "chars": 298,
    "preview": "\nconst caller = require('caller');\nconst config = require('./config');\n\nconst data = require('./data');\nconst biz = requ"
  },
  {
    "path": "src/server/cross.js",
    "chars": 577,
    "preview": "\nconst fn = (res) => {\n\n\t// Website you wish to allow to connect\n\tres.setHeader('Access-Control-Allow-Origin', '*');\n\n\t/"
  },
  {
    "path": "src/server/index.js",
    "chars": 2870,
    "preview": "\nconst http = require('http');\n\nconst config = require('../config');\nconst routes = require('./routes');\nconst processPu"
  },
  {
    "path": "src/server/public/index.js",
    "chars": 1770,
    "preview": "\nconst fs = require('fs');\nconst path = require('path');\n\nconst config = require('../../config');\nconst mime = require('"
  },
  {
    "path": "src/server/public/mime.js",
    "chars": 443,
    "preview": "\nconst me = {\n\tcss: 'text/css',\n\tgif: 'image/gif',\n\thtml: 'text/html',\n\tico: 'image/x-icon',\n\tjpeg: 'image/jpeg',\n\tjpg: "
  },
  {
    "path": "src/server/routes/index.js",
    "chars": 496,
    "preview": "\nconst config = require('../../config');\nconst data = require('../../data');\nconst bizDo = require('../../biz/do');\ncons"
  },
  {
    "path": "src/server/routes/parseQueryStr.js",
    "chars": 1558,
    "preview": "\nconst url  = require('url');\nconst qs = require('qs');\n\nconst parseQueryStr = (str) => {\n\tlet query;\n\tlet errArg;\n\tlet "
  },
  {
    "path": "test/forExamples/index.js",
    "chars": 1129,
    "preview": "\nconst fs = require('fs');\nconst path = require('path');\nconst cp = require('child_process');\n\nconst main = () => {\n\tcon"
  },
  {
    "path": "test/forExamples/testCases/01-hello-world.js",
    "chars": 289,
    "preview": "\nconst me = [\n\n\t'/say/hi',\n\t{\n\t\tparams: {\n\t\t\tname: 'owen',\n\t\t\tage: 100\n\t\t},\n\n\t\tresult: {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t"
  },
  {
    "path": "test/forExamples/testCases/02-complex-url-params.js",
    "chars": 393,
    "preview": "\nconst me = [\n\n\t'/foo/bar',\n\t{\n\t\tparams: {\n\t\t\tname: \"owen\",\n\t\t\tobj: {\n\t\t\t\tdate: \"2019-05-01\"\n\t\t\t},\n\t\t\tarr: [\n\t\t\t\t1,\n\t\t\t\t"
  },
  {
    "path": "test/forExamples/testCases/03-returning-an-error.js",
    "chars": 138,
    "preview": "\nconst me = [\n\n\t'/do/somethingIsWrong',\n\t{\n\t\tresult: {\n\t\t\tsuccess: false,\n\t\t\terror: \"something is wrong\"\n\t\t}\n\t},\n];\n\nmod"
  },
  {
    "path": "test/forExamples/testCases/04-throwing-an-error.js",
    "chars": 152,
    "preview": "\nconst me = [\n\n\t'/do/say/hi',\n\t{\n\t\tverify(result) {\n\t\t\treturn result.error.message.indexOf('something is wrong') >= 0;\n\t"
  },
  {
    "path": "test/forExamples/testCases/05-api-directory.js",
    "chars": 403,
    "preview": "\nconst me = [\n\n\t'/say/hi',\n\t{\n\t\tparams: {\n\t\t\tname: 'owen',\n\t\t\tage: 100\n\t\t},\n\n\t\tresult: {\n\t\t\t\"success\": true,\n\t\t\t\"data\": "
  },
  {
    "path": "test/forExamples/testCases/06-with-database.js",
    "chars": 559,
    "preview": "\nconst me = [\n\n\t'/user/login?username=owen&password=123',\n\t{\n\t\tbefore: [\n\t\t\t'/user/register?username=owen&password=123',"
  },
  {
    "path": "test/forExamples/testCases/07-static-resources.js",
    "chars": 707,
    "preview": "\nconst me = [\n\n\t'/',\n\t{\n\t\tverify(result) {\n\t\t\treturn result.indexOf('Hello, world!') >= 0;\n\t\t}\n\t},\n\n\t'/images',\n\t{\n\t\tver"
  },
  {
    "path": "test/forExamples/testCases/99-options.js",
    "chars": 130,
    "preview": "\nconst me = [\n\t'/about',\n\t{\n\t\tresult: {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\t\"version\": \"1.0.0\"\n\t\t\t}\n\t\t}\n\t},\n];\n\nmodule.expo"
  },
  {
    "path": "test/index.js",
    "chars": 47,
    "preview": "\nrequire('./forExamples');\nrequire('./tests');\n"
  },
  {
    "path": "test/tests/api-folder/api/about.js",
    "chars": 40,
    "preview": "\n// Test\n// http://localhost:3000/about\n"
  },
  {
    "path": "test/tests/api-folder/index.js",
    "chars": 45,
    "preview": "\nconst noapi = require('../../..');\nnoapi();\n"
  },
  {
    "path": "test/tests/api-folder/test/cases.js",
    "chars": 152,
    "preview": "\nconst me = [\n\t'/about',\n\t{\n\t\tresult: {\n\t\t\t\"success\": false,\n\t\t\t\"error\": \"The handler ./biz/about.js does not exists.\"\n\t"
  },
  {
    "path": "test/tests/default/biz/get.js",
    "chars": 91,
    "preview": "\nconst fn = async (name, obj, arr) => {\n\treturn {name, obj, arr};\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "test/tests/default/biz/post.js",
    "chars": 91,
    "preview": "\nconst fn = async (name, obj, arr) => {\n\treturn {name, obj, arr};\n};\n\nmodule.exports = fn;\n"
  },
  {
    "path": "test/tests/default/index.js",
    "chars": 45,
    "preview": "\nconst noapi = require('../../..');\nnoapi();\n"
  },
  {
    "path": "test/tests/default/test/cases.js",
    "chars": 970,
    "preview": "\nconst me = [\n\t'/',\n\t{\n\t\tresult: {\n\t\t\t\"success\": true,\n\t\t\t\"data\": \"Welcome to Noapi.\"\n\t\t}\n\t},\n\n\t'/xxx',\n\t{\n\t\tresult: {\n\t"
  },
  {
    "path": "test/tests/index.js",
    "chars": 575,
    "preview": "\nconst fs = require('fs');\nconst path = require('path');\nconst cp = require('child_process');\n\nconst main = () => {\n\tcon"
  }
]

About this extraction

This page contains the full source code of the hiowenluke/noapi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 72 files (30.1 KB), approximately 11.5k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!